解一元三次方程

虽然我是一个新手,按”规矩“应该要经常在博客里面把自己的错误都写出来做个总结,但是我比较保守,总是觉得博客是一个社交平台,一些相对不太成熟的东西还是写个word文档自己存起来好,在博客里面发出来的都是一些比较有感悟、用心搞过的东西(虽然可能还是不成熟的)。总而言之,用心创作,如有错漏,请多见谅、多指正。

前排放一下试错的过程:(其实我还拿洛谷试验了几次)
这道题之所以试验了这么多次(都是掩饰,倒不如说是WA了这么多次),就是因为反复试了很多细节。所以说,dalao们觉得平平无奇、不言自明的东西,到了新手那里都成了细节和新鲜事物(捂脸)。
那么这个题我到底品出来多少细节呢?直接上一段最终的代码:

#include<cstdio>
using namespace std;
double a,b,c,d;
int count;
double ans(double x){return x * x * x * a + x * x * b + x * c + d;
}
void divide(double x1,double x2){if(x2 - x1 < 0.001){ //细节1 if(count > 0) printf(" ");printf("%.2lf",x1),count++;return;}double mid = (x1 + x2) / 2;if(ans(x1) * ans(mid) <= 0) divide(x1,mid);else if(ans(x2) * ans(mid) <= 0) divide(mid,x2);//细节2
}
void solve(double x,double y){//细节3 double i;for(i = x;i <= y - 1 && count < 3;i++){if(ans(i) * ans(i + 1) <= 0) divide(i,i + 1);i += 0.5;//细节4 }
}
int main(){scanf("%lf %lf %lf %lf",&a,&b,&c,&d);//细节5 solve(-100,100);return 0;
}

(u1s1,我觉得五个细节试了十五六次也不算多)
接下来我们就分别讨论一下这五个细节。
首先这个题范围如此之大,假如要暴搜的话最坏的情况需要搜上20000次,肯定TLE无疑,因此显然是个分治 (更有说服力的解释是,这个题是分治里面的题)。
有了这个思路,才好去看一些实际操作中的细节。
先从细节3、细节5开始,这俩其实异曲同工,说的都是变量类型的问题。细节3指的是,不要忘记函数的变量和放进去的变量要是同一个类型的;细节5指的是,如果想进行浮点数运算,就不要把浮点数跟整形混一起算(大多数需要浮点的题基本上输入也有浮点)。这些东西虽然是基础,但是对于一个新手还是经常错,而且这个还不太容易察觉(举个最浅显的例子,虽然我现在还是会scanf忘记打&,但是程序一输入就报错就会第一时间找自己是不是没有打&;不过如果是printf加了&,一般就很长时间才能发现,因为能让一段平常的代码输出一对很鬼畜的东西的不止这个),所以值得拿出来说一说。另外,一般把整型转成浮点最方便的方法就是*1.0,但是千万不要给写成 *0.1,以及像这种题通常都是要算一下百分比,还得记得 *100……
接下来的两个是细节1、细节4,这两个都与四舍五入有关系。
当年高中老师在信息课上讲Python的时候,曾经说过一个整数的四舍五入的很好的方法:把这个数据+0.5,然后取整。然而在细节1中我们直接取到了0.001而不是0.005(尽管这俩都能过),这是因为double取值的时候会自动的四舍五入而不是像整型的除法或者ceil那样简单粗暴的向下或上取整,因此如果出现正好卡在千分位是4或5的时候,取到0.005就会导致这个数从向下的那一边给拉到了向上的一边,而如果已经小于0.001了,那么这个数连千分位都可以说是确定的(或者说,其实更科学的取法应该是取到0.0005?),因此我们随便从x1、x2里面挑一个就行了。至于为什么不给x1加个数输出来替换掉这个膨胀的寻找范围,正如上所述,如果范围不够小,而加上的数又比较大(这里我认为超过0.001的都叫做大)很难保证这个区间内的随便哪一个值加上这个预设的数都不会移位;但是如果加上的数小,那么加与不加还有什么区别呢?结果还是不能保证这个区间内所有的数加上了都可以在正确的一侧,因为这个区间本身就太大了,要是把区间取得足够小,也就不必再费心考虑这个加一个数的问题了。
至于细节4,这个操作可能看起来比较迷惑,但是是有用处的。由于细节1,我们不得不把区间取得很小,加上这道题的限制是两个解的差至少是1,因此一个区间[i,i+1]搜过之后,如果这个解恰好就卡在i+1上,那么下次搜[i+1,i+2]的时候就会发生重复,所以如果确实找到一个解,就要额外增加一下i,人为防止出现取重的可能性。由于四舍五入原理加上原题的限制,我选择了+0.5,这是为了防止错过下一个区间的值而又可以防止取重复,如果+1的话就会导致跳过解的可能性。
最后一个就是细节2,也是整个题最玄学的一个点。我们一开始学二分的时候,老师都会特别提醒,说一定要在二分的时候写(l,mid)和(mid+1,r),千万不能把mid给丢了,否则会导致程序整个RE;然而这个题就是要写(l,mid)(mid,r),啥也不能加,0.01不行,0.001不行,连个基本已经没卵用的0.0001也不行,这是为什么?
要解答这个问题,我们需要知道基本的二分为什么一定要有这个+1(整型)。因为在一般的二分当中,结束条件的要求是极小,这个极小往往是l=r。如果不进行+1,就会导致l-r=1的时候总有mid和l的差值为1不变,结果这个二分就一直卡在这里,无法结束,直至RE。这种情况几乎会发生在每一个数据中,因此必须要+1。然而这题压根就不害怕自己mid取不出来,因为我们再怎么说,这个mid它是一个double,小数点后12位,万亿分位都能取,还怕这个才千分位的判断?而且我们并不需要取到l=r为止,只要取到一定范围之内就可以,同时mid的潜力完全可以满足这个范围的要求,因此不必要再加。既然可以不加,那么为什么加了就是不对呢?因为在加了之后,我们人为地改变了下一次的取值范围,这种改动一多,就会导致偏的越来越大,结果取不到需要的值,因为double毕竟是可以取12位,他允许我们忽略细节,自然就带来了巨大的误差空间,这个+0.001不要说是导致错过一些解,甚至都有可能导致一个区间直接被跳过去,尤其是如果某个解恰巧是个整数或者恰巧就等于r,这个加上的数就可能导致这个解被跳过去,不管到底加的是有多小(雄辩的事实是,尽管我加了个10^-12,也就是double的极限,还是能跳掉卡在r的整数解)。
以上就是这一道题产生的各种自认为所谓细节的讨论。总之其实多数还是一些基础性的问题,应该是平时要多注意的坑;其他的一些东西,就需要我们能严谨的思考,如果真出现了很玄学的东西,那我们也只能微笑着面对它,然后请它上博客“青史留名”了。
Thank you for reading!

解一元三次方程方程问题细节探讨相关推荐

  1. 盛金公式解一元三次方程_一元三次方程解法(卡尔丹公式法盛金公式法)

    卡尔丹公式法 特殊型一元三次方程 X^3+pX+q=0 (p.q∈R) 判别式Δ=(q/2)2+(p/3)3 卡尔丹公式 X1=(Y1)(1/3)+(Y2)(1/3) X2= (Y1)(1/3)ω+( ...

  2. 问题三十七:C++怎么解一元四次方程?(2)——怎么解一元三次方程

    37.2 怎么解一元三次方程? 用"盛金公式"求解: ----------------------------------------------main.cpp -------- ...

  3. 盛金公式解一元三次方程_【国际数学竞赛】高次方程求根

    对于一元二次方程 ,我们由求根公式可得: . 对于一元三次方程 ,我们有 卡尔丹公式法和盛金公式法.不过公式比较冗长.不易计算,但我们还是有方法计算的,那么如果是一元四次.一元五次甚至更高呢? 遇到高 ...

  4. 解一元三次方程noip2001

    题目描述 有形如:ax^3+bx^2+cx^1+dx^0=0ax3+bx2+cx1+dx0=0 这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,da,b,c,d均为实数),并约定该方程存在 ...

  5. 牛顿迭代法解一元三次方程

    题目描述 有形如:ax^3+bx^2+cx^1+dx^0=0ax3+bx2+cx1+dx0=0 这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,da,b,c,d均为实数),并约定该方程存在 ...

  6. 盛金公式解一元三次方程_盛金公式解一元三次方程

    Module Shengjin_mod Implicit None contains Function Cubic_equation(Co) Result (X) !盛金公式求解一元三次方程 !默认浮 ...

  7. c++解一元三次方程

    求解一元三次方程组 转自:http://blog.csdn.net/u012221917/article/details/17175793 float f(float w_f, float x_f, ...

  8. 如何用java解一元二次方程方程

    下面是一个解一元二次方程的 Java 程序: import java.util.Scanner;public class Main {public static void main(String[] ...

  9. matlab复数方程的根,matlab解一元三次方程,得到的都是复数根。

    对于你昨天的那个方程,是典型的非线性方程,我修改了程序,用fsolve函数来解,程序在下面.先新建一个m文件,再把以下全部程序直接复制进m文件中,运行即可,不要在主窗口中运行,用m文件来写程序,比直接 ...

最新文章

  1. 数据结构与算法常用名词术语整理
  2. Java 判断一个字符串是否为数字类型
  3. 1个ieee1394端口_如何使用圆形端口进行波导激励和终止
  4. css3 自定义滚动条样式
  5. android新建项目错误,新建Android项目出错
  6. 关于学习Python的一些心得
  7. VSCode: 快捷键大全
  8. 如何通过项目周报获取项目信息-周报模板
  9. ArcGIS 对DEM数据进行剖面分析
  10. 【python基础】windows下python环境版本更新教程
  11. burp的安装和配置
  12. 数据库中查询经纬度距离远近
  13. 情人节程序员用HTML网页表白【在一起计时】 HTML5七夕情人节表白网页源码 HTML+CSS+JavaScript
  14. 绝对良心提供百度网盘的jdk1.8源码下载包含sun包的
  15. 32位oracle10,Oracle10g32位升级到64位方法
  16. Http请求的header头解析
  17. 记忆化搜索 day48
  18. 用户名不在sudoers文件中,此事将被报告
  19. 新科高清GPS地图4.04版测评
  20. 1346:【例4-7】亲戚(relation)

热门文章

  1. __attribute__中的constructor和destructor
  2. 7-40 奥运排行榜
  3. 用selenium在python下实现批量网页 截图
  4. mysql自动排序_mysql自动排序
  5. PDF矢量图片转为EPS格式图片的方法
  6. R数据分析:变量间的非线性关系,多项式,样条回归和可加模型
  7. 你怎么看待互联网创业的国外问卷调查?
  8. Unity3D开发工程师
  9. NGO招志愿者翻译,请分享
  10. 如何选定搭建个人独立博客工具