buaaoo_first_improvement
优化,还是不优化,这是个问题
本讨论仅基于程序基本上正确的情况下。
(一)第一次作业
众所周知,本次作业没有优化到100分的都进入了B组或者C组,所以事实上本次作业的优化是十分简单的,在这里提几句。
(1)合并同类项
最简单的做法也是最高效的做法,通过Hashmap,将指数存为key,将系数作为对应value,那么可以很简单的将同类项进行合并。
(2)对项进行省略
当然,+0,0*,1*,等这样无意义的项,仅需要做特殊判断,那么就可以直接省略,从而缩减表达式的长度。
(3)对项进行排序
对于负数,会比正数多一个不必要的符号,所以我们可以直接将负号作为减号放到项中,所以最好的做法是对所有在Hashmap里的系数做一个判断,先输出正项,若无正项,则输出负项。
经过以上三种处理,第一次作业便可以完美的将表达式化简为最简形式。
(二)第二次作业
本部分是本次讨论的重点部分。
第二次作业开始,大家的算法实现就变得五花八门,面向过程的,面向对象的,不一而足。
所以在这里我要基于一个看起来似乎是解决本次作业最好的算法来讨论化简。
根据题目可以得知,每一个原子项可以写成如下形式(请原谅我的超长正则):
(([+-]{0,3}\\d+)|([+-]{0,2}x(\\^[+-]?\\d+)?)|([+-]{0,2}sin\\(x\\)(\\^[+-]?\\d+)?)|([+-]{0,2}cos\\(x\\)(\\^[+-]?\\d+)?))(\\*(([+-]?\\d+)|(x(\\^[+-]?\\d+)?)|(sin\\(x\\)(\\^[+-]?\\d+)?)|(cos\\(x\\)(\\^[+-]?\\d+)?)))*
所以首先应该做的是对于原子项中的因子合并,从而形成形如a*x^b*sin(x)^c*cos(x)^d的形式,进而大大缩短了处理难度,下面放出我的合并函数:
for (String it : ob) {
if (it.matches("[+\\-]?\\d+")) {
num = num.multiply(new BigInteger(it));
}
else if (it.matches("[+-]?sin\\(x\\)(\\^[+-]?\\d+)?")) {
if (it.substring(0, 1).matches("-")) {
num = num.multiply(new BigInteger("-1"));
}
sin = "sin(x)^" + combine(sin, it);
}
else if (it.matches("[+-]?cos\\(x\\)(\\^[+-]?\\d+)?")) {
if (it.substring(0, 1).matches("-")) {
num = num.multiply(new BigInteger("-1"));
}
cos = "cos(x)^" + combine(cos, it);
}
else if (it.matches("[+-]?x(\\^[+-]?\\d+)?")) {
if (it.substring(0, 1).matches("-")) {
num = num.multiply(new BigInteger("-1"));
}
x = "x^" + combine(x, it);
}
}
private String combine(String sss, String it) {
Pattern p = Pattern.compile("\\^");
Matcher m = p.matcher(it);
BigInteger b1;
BigInteger b2;
if (sss.equals("")) {
if (m.find()) {
String t = it.substring(m.start() + 1);
return t;
}
else {
return "1";
}
}
else {
Pattern pp = Pattern.compile("\\^");
Matcher mm = pp.matcher(sss);
if (mm.find()) {
b1 = new BigInteger(sss.substring(mm.start() + 1));
if (m.find()) {
b2 = new BigInteger(it.substring(m.start() + 1));
}
else {
b2 = new BigInteger("1");
}
b1 = b1.add(b2);
return b1.toString();
}
}
return "0";
}
便将每一原子项中的同类因子合并,之后应该在项内做排序,从而得出如上述规范化的式子,即a*x^b*sin(x)^c*cos(x)^d的形式,这里就省略排序代码。
将通过+-分隔的每一原子项按照如上规则处理好之后,可以进行存入Hashmap处理,处理方式如下:
设立Poly类,其中包含BigInteger参数三个,分别为b、c、d,即x,sin(x),cos(x)各自的指数(若不存在此因子则指数为0),那么可以将此三元组作为key值,将a,即系数作为value,形成一个新的Hashmap,形式为Hashmap<Poly, BigInteger>,可知,对每个相同形式的项,均可以用前述方法处理并合并为同类项。
对于三角函数化简公式,比较简单的有如下几种:
sin(x)^2 + cos(x)^2 = 1
1 - cos(x)^2 = sin(x)^2
1 - sin(x)^2 = cos(x)^2
进阶版的有如下形式:
sin(x)^4 + 2 * sin(x) ^2* cos(x)^2 + cos(x)^4 = 1
sin(x)^4 - cos(x)^4 = sin(x)^2 - cos(x)^2
......
事实上,若想比较好的化简,应该先将进阶版部分的三角函数进行化简(即降次,否则会导致需要重复使用基础版化简公式,导致TLE)
由于我们的存储方式,可以知道,对于进阶版化简部分,可以枚举出几个典型的公式,进行if-else判断(方法繁琐但不容易出错),将常见的进阶版公式化简之后,就可以愉快的开始基础版化简了。
· 而根据我们之前所讨论的Hashmap存储方法,可知两对三元组为<b1, c1, d2>、<b2, c2, d2>,若满足:
1.b1 == b2
2.(abs(c1 - c2) == 2 && d1 == d2) || (abs(d2 - d1) == 2 && c1 == c2)
或
3.b1 == b2
2.(c1 - c2 == 2 && d1 - d2 == -2) || (d2 - d1 == 2 && c1 - c2 == -2)
即可将含有基础版化简形式的部分项化简,若分别考虑两者系数a1, a2,则会保留下某一三元组的部分式子。而上述基础版化简的时候要记得用if-else判断为哪种形式,否则化简出来的式子会含有^0之类不应该存在的部分。
在化简的时候需要注意的是,在Hashmap存化简之后的项的时候,要用keycontains检测是否已经存在了项,不要将已有的项覆盖掉:)
最后处理按照第一次作业类似的方法(排序,正项提前等)即可将化简做到比较好的程度。
(三)第三次作业
具体请见作业博客,网址如下:
https://www.cnblogs.com/dxy1999/p/10585219.html
最后, 我想说,其实化简表达式并不完全是为了分数,而更应该从中学到如何将OO课程学的更好。试问,如果在化简的时候对于自己的类的概念不清晰,又怎能写出正确的代码呢?疯狂面向过程写代码,又会创造出多么长的代码呢?愿我们共勉。
简,你化不化,它就在那里
buaaoo_first_improvement的更多相关文章
随机推荐
- 使用sshpass同时更新一台ubuntu和一台CentOS
1.在ubuntu上安装sshpass sudo apt install sshpass 2.分别在两台的root路径下放上升级脚本: cent:/root/upgrade.sh #!/bin/bas ...
- python实现猜字游戏
import randomx = random.randint(0,99)while(True): num = input("please input a number\n") i ...
- java 判断语句和循环语句
一.判断语句:if和switch if(关系表达式1) { 语句体1; }else if (关系表达式2) { 语句体2; }…else { 语句体n+; } switch(表达式) { case 值 ...
- Jmeter 逻辑控制器总结
本文主要总结Jmeter的逻辑控制器: 逻辑控制器下一共16个控制器: 1.foreach controller循环控制器 定义变量数组,按数组遍历循环 2.simple controller 简 ...
- Kubernetes基本功能
说明 目前kubernetes的资料介绍很多也很深刻,本文只是做一个针对自己学习k8s过程的介绍,仅仅是学习笔记的记录. 一.基本使用 1. 命令行 集群信息 Namespace 信息 Control ...
- [Luogu P2296][NOIP 2014]寻找道路
emmm交了第8次才过. 这道题目测一道单源最短路问题,因此dijkstra或者spfa板子先准备好.因为题中对最短路有限定: 路径上的所有点的出边所指向的点都直接或间接与终点连通. 在满足条件1的情 ...
- [Reinforcement Learning] 马尔可夫决策过程
在介绍马尔可夫决策过程之前,我们先介绍下情节性任务和连续性任务以及马尔可夫性. 情节性任务 vs. 连续任务 情节性任务(Episodic Tasks),所有的任务可以被可以分解成一系列情节,可以看作 ...
- PHP带参数传值调用python脚本
PHP主要用在服务器端做网站后台开发,有些功能用PHP来实现有点费劲或者无法实现,现在在学习python,同样是脚本语言,感觉python能做的事情PHP不一定能胜任.但是现在大部分的网站后台也是用P ...
- python双端队列-collection模块
双端队列(double-ended queue,或者称deque)在需要按照元素增加的顺序来移除元素时非常有用.其中collection模块,包括deque类型. 使用实例:
- 虚拟机有QQ消息时宿主机自动弹窗提示
因为是检测窗口实现的,所以要求设置会话窗口自动弹出,而且看完消息就把QQ消息窗口关掉... 虚拟机端 #! /usr/bin/env python # -*- coding: utf-8 -*- fr ...