OO第1.2次作业·魔鬼的三角函数化简
多年以后,面对办公室的屏幕,我会回忆起开始肝第二周OO作业的那个遥远的下午。那时的程序是一个一两百行的符号求导,基类与接口在包里一字排开,工整的注释一望到底
谁能想到,接下来的十几个小时我要经历什么样的噩梦(
转自我的个人博客
问题描述
我们面临的问题很简单:给定一个符号表达式E,E由幂函数、正弦函数和余弦函数的乘积加和而成(严谨定义略),求与E等价的尽可能短的表达式E'
即:
形如2*x*sin(x)^2+sin(x)+4*cos(x)+6*sin(x)*cos(x)^-2
形式的表达式合法,而若给定
sin(x)^2+cos(x)^2
,则最优解为1
胡乱分析
这个问题,第一眼看上去是个贪心,因为很容易想到,对于像sin(x)^4+2*sin(x)^2*cos(x)^2+cos(x)^4
这样的表达式,只要每次合并Exp*sin(x)^2 + Exp*cos(x)^2
,最后能得到最优解。合并经常是正收益的。
但是反例也很好举出:3*sin(x)^-2 + cos(x)^-2
,类似这种表达式,合并后并非最优
实际上由于字符串长度在某因子系数为-2
,-1
,0
和1
时会因为省略输出而变短,在合并后会发生难以控制的变化
但是简单想想就知道,大部分时候无脑合并应该是正收益。所以这个贪心可以作为一个baseline
另外一个问题来自合并顺序。考虑A和B可合并,B和C可合并,但A和C不可合并,那么优先合并哪两项?
因此简单的说我们要解决两个问题:
- 合与不合
- 先合谁
十分NP了。NP的最优解只能靠搜索求
暴搜是可能T或爆栈的,剪枝又太麻烦,容易写错,不太想走这条路子。想起来NOIP2015 D1T3 斗地主,考场上就有人用多个策略贪心取最优解的做法骗满。说是骗分,但是这种做法其实更适合实际生产环境应用。这个思想很像Embedding。所以决定借鉴一下
准备工作
一般地,对于所有这样的表达式项我们可以以一个三元向量简化表示,如
4*sin(x)^2*cos(x)
,可以以(0,2,1)
和其系数4
表示
而对于两个可合并的项,容易证明,一定满足其指数三元向量的差为(0,2,-2)
或(0,-2,2)
进一步的,对于一个给定的表达式,若其系数表示为root = (a,b,c)
,那么它及
sin(root) = (a,b+2,c)
cos(root) = (a,b,c+2)
这三者中的任意两者的线性组合可以转化为另外两者的线性组合
结合这种表述形式,我们实现一个可哈希的三元向量类,作为一个HashMap
的键,将每一项的系数作为值,这样做的首要考虑是方便合并同类项,次要考虑是方便查找和给定项存在转化关系的项(几乎常数级的查询复杂度)
贪心策略
这一步主要解决第一个问题:合与不合
采用如下的组合策略:
- 对于三角函数因子系数不含
-2
、-1
的项,无脑合并,优先合并成root
,不足以补成root
的三角函数项,转换成系数绝对值较大的三角函数因子。迭代至不能再合并为止,作为初始解 - 对于三角函数因子系数不含
-2
、-1
的项,无脑合并,检查root+sin
、root+cos
、sin+cos
三种情况中输出最短的情况,转化至这种情况。迭代至不能再合并为止。若长度得到优化接收当前解作为新解 - 对于所有项,执行类似1的操作,若长度得到优化接受当前解作为新解
- 对于所有项,执行类似2的操作,若长度得到优化接受当前解作为新解
这些策略可能不是最优的,但是实测已经能卡掉绝大多数情况了,所以也没有进一步打磨。
引入随机化
解决第二个问题:先合谁。
实际上裸的多策略贪心性能已经不错了,我们可以通过随机打乱项的顺序,将目前的方法改进为一个蒙特卡罗方法,进一步消除合并顺序的影响。
每次求一个新解前,用键集合keySet
初始化一个链表并用Collections.shuffle()
打乱顺序,然后使用上述的贪心策略求一个解,若优于既有解,接受新解。迭代这个过程
我只迭代了50次,因为这次作业的输入规模(100)很小,这个数量应该足够了。
进一步的讨论
目前的随机化只是简单的打乱顺序。是否可以考虑使用一些智能随机算法,比如遗传、蚁群、PSO、退火?
使用遗传算法的可能做法
将项的系数与指数三元组作为项的编码,将全部项的编码降序排列作为表达式的编码
- 突变算子:
- 分裂突变:随机分裂某一项为
sin^2+cos^2
的形式,开销是常数级 - 合并突变:随机选择可合并的某两项合并,复杂度常数级。为了让合并突变是常数级操作,需要维护一个Flag确定每一项在当前编码中是否可合并、合并对象的索引或引用
- 分裂突变:随机分裂某一项为
- 交叉算子:对于编码A中的子串A'和B中的子串B',A'和B'同源(由原始表达式中的相同项合并或分裂生成),那么一定有A'和B'的补CAA'、CBB'也同源。将A'与CBB'拼接、B'与CAA'拼接,作为两个子代。为了快速找到两个同源的子串,需要对每个编码维护一个并查集。
- 适应函数与选择算子:显而易见,选择编码对应的表达式字符串长度作为适应函数。
总结
这次优化设计,我的感受是,一个优秀的近似解算法可能会比一个确定解算法更实用,因为它的时空需求更少,而解的质量并不会差的太多。
OO第1.2次作业·魔鬼的三角函数化简的更多相关文章
- OO第二次博客作业——电梯调度
OO第二次博客作业——电梯调度 前言 最近三周,OO课程进入多线程学习阶段,主要通过三次电梯调度作业来学习.从单部电梯的傻瓜式调度到有性能要求的调度到多部电梯的调度,难度逐渐提升,对同学们的要求逐渐变 ...
- OO第二次博客作业—17373247
OO第二次博客作业 零.写在前面 OO第二单元宣告结束,在这个单元里自己算是真正对面向对象编程产生了比较深刻的理解,也认识到了一个合理的架构为编程带来的极大的便利. (挂三次评测分数 看出得分接近等差 ...
- OO第二单元作业——魔鬼电梯
简介 本单元作业分为三次 第一次作业:第一次作业要实现单部简单电梯,停靠所有楼层,无载客容量,性能分考量电梯运行时间. 第二次作业: 第二次作业实现多部电梯,电梯数量由初始化设定,每部电梯都停靠所有楼 ...
- OO第二次博客作业(第二单元总结)
在我开始写这次博客作业的时候,窗外响起了希望之花,由此联想到乘坐自己写的电梯FROM-3-TO--1下楼洗澡,然后······ 开个玩笑,这么辣鸡的电梯肯定不会投入实际使用的,何况只是一次作业.还是从 ...
- OO第1~3次作业总结
作业1——多项式运算 基于度量和类图分析设计 先看Metrics插件做出的复杂度分析: 乍一看没有红色报警,其实是因为选中某一行时会自动将该行改为黑色,无论之前是红色还是蓝色emmm 真正展开第一行时 ...
- BUAA OO 2019 第四单元作业总结
目录 第四单元总结 总 UML UML 类图 UML 时序图 UML 状态图 架构设计 第十三次作业 第十四次作业 课程总结 历次作业总结 架构设计 面向对象方法理解 测试方法理解与实践 改进建议 尽 ...
- BUAA OO 2019 第三单元作业总结
目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...
- OO第四单元UML作业总结暨OO课程总结
目录 目录一.第四单元UML两次作业架构设计第一次作业第二次作业二.架构设计总结与OO方法理解演进三.测试理解与实践演进四.课程收获总结五.课程改进建议六.尾声 一.第四单元UML两次作业架构设计 第 ...
- oo第二次博客作业
多线程协同与同步控制总结 第五次作业-多线程电梯 本次作业是我第一次接触多线程,建立了请求模拟器.调度器和电梯运行三种线程.请求模拟器负责在输入后识别有效请求:调度器在扫描有效请求后将新的请求加入请求 ...
随机推荐
- 攻防世界 reverse EasyRE
EasyRE 主函数 int sub_401080() { unsigned int lens; // kr00_4 signed int i; // edx char *v2; // esi cha ...
- Linux—用户新建目录和文件的默认权限设置:umask详解
关注微信公众号:CodingTechWork,一起学习进步. 引言 我们有没有思考过一个问题,在登录Linux系统后,我们创建的目录或者文件的权限,为什么每次创建都是统一的?我们做以下实验:新建一 ...
- java例题_37 有 n 个人围成一圈,顺序排号。从第一个人开始报数(从 1 到 3 报数),凡报到 3 的人退出圈子, 3 问最后留下的是原来第几号的那位。
1 /*37 [程序 37 报数] 2 题目:有 n 个人围成一圈,顺序排号.从第一个人开始报数(从 1 到 3 报数),凡报到 3 的人退出圈子, 3 问最后留下的是原来第几号的那位. 4 */ 5 ...
- Python数据分析入门(十四):数据分析中常用图
折线图: 折线图用于显示数据在一个连续的时间间隔或者时间跨度上的变化,它的特点是反映事物随时间或有序类别而变化的趋势.示例图如下: 折线图应用场景: 折线图适合X轴是一个连续递增或递减的,对于没有规律 ...
- java面试-公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解
一.公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解 公平锁:多个线程按照申请的顺序来获取锁. 非公平锁:多个线程获取锁的先后顺序与申请锁的顺序无关.[ReentrantLock 默认非公平.s ...
- 承接上一篇,whale系统开篇,聊聊用户认证
写在前面 上次老猫和大家说过想要开发一个系统,从简单的权限开始做起,有的网友表示还是挺支持的,但是有的网友嗤之以鼻,认为太简单了,不过也没事,简单归简单,主要的还是个人技术的一个整合和实战. 没错,系 ...
- manjaro找不到默认键盘布局
1 问题描述 manjaro安装fcitx后,没有默认的键盘布局,不是这样: 而是: 2 解决方案 解决方案在启动fcitx时就已经有提示了: 缺少了libjson-c这个库,直接使用pacman搜索 ...
- JetBrains系列IDE无法输入中文
1 问题描述 环境Linux+fcitx,JetBrains的IDE无法输入中文,包括IDEA,PyCharm,WebStorm,CLion等等. 2 解决方案 Linux下一般使用fcitx进入中文 ...
- Magicodes.IE.ASPNETCore之多样化接口使用
1.安装包 Install-Package Magicodes.IE.AspNetCore 2.开始配置 在Startup.cs的Configure()方法中,在UseRouting()中间件之后,注 ...
- .NET6 平台系列1 .NET发展史之.NET Framework简介
系列目录 [已更新最新开发文章,点击查看详细] 自1995年互联网战略日以来最雄心勃勃的事业 -- 微软.NET战略, 2000年6月30日. 微软公司于2002年2月13日正式推出第一代.N ...