P1024 一元三次方程求解
1. 思路
-
这题看分组是二分求解,然而这个题的二分不是普通的二分,因为有三个答案,所以需要把数据分段,至于怎么分,重点在且根与根之差的绝对值≥1 这句话,我们以1为长度,把-100到100看作200段,然后每段使用二分
for(int i=-100;i<100;i++){ double res = check(i,i+1); }
-
当且仅当x1<x2,f(x_1)* f(x_2)<0的时候存在解,那么这个就是我们check函数
inline double fun(double x){ return a*x*x*x+b*x*x+c*x+d; } if(fun(l)*fun(mid)>0) l = mid; else r = mid;
-
这题有个大问题,那就是如果不加限制的话,右节点是会访问两次的,比如当i是-100时,我们会检查一遍-100和-99,但是当i是-99时,我们又会访问一遍-99和-98,而-99就访问了两次,如果恰巧-99就是一个解的话,那么这个解我们会得到两次,从而影响正确结果
我最初的做法是,把右节点左移0.0001,由于我们的精度要求是0.001,那么移动0.0001应该没什么问题,当然,最后还是证明有问题
最终的解决办法是:先特判左节点为正确答案,然后返回之后再特判返回值是不是右节点,(有点复杂,但是我缺一个他就报错...,那位大牛帮忙指出下...QAQ)
注水代码
#include<iostream> #include<cmath> using namespace std; double a,b,c,d; inline double fun(double x){ return a*x*x*x+b*x*x+c*x+d; } double check(double l,double r){ double mid; if(fabs(fun(l)-0)<1e-8)return l; if(fun(l)*fun(r)>0)return -111; while(r-l>0.001){ mid = (l+r)/2; if(fun(l)*fun(mid)>0) l = mid; else r = mid; } return l; } //-0.35 1.00 4.00 int main(){ freopen("data.in","r",stdin); cin>>a>>b>>c>>d; int e = 0; for(int i=-100;i<100;i++){ double res = check(i,i+1); if(fabs(res-(i+1))<0.001)continue; if(res!=-111){ printf("%.2lf ",res); if(++e==3)break; } } return 0; }
题面:
题目描述
有形如:ax^3+bx^2+cx^1+dx^0=0a**x3+b**x2+c**x1+d**x0=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,da,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在-100−100至100100之间),且根与根之差的绝对值\ge 1≥1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后22位。
提示:记方程f(x)=0f(x)=0,若存在22个数x_1x1和x_2x2,且x_1<x_2x1<x2,f(x_1) \times f(x_2)<0f(x1)×f(x2)<0,则在(x_1,x_2)(x1,x2)之间一定有一个根。
输入格式
一行,44个实数A,B,C,DA,B,C,D。
输出格式
一行,33个实根,并精确到小数点后22位。
输入输出样例
输入 #1复制
1 -5 -4 20
输出 #1复制
-2.00 2.00 5.00