一元三次方程求解 (laoj1114)
有形如:ax^3+bx^2+cx+d=0这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后4位。
提示:记方程f(x)=0,若存在2个数x1和x2,且x1 输入格式:输入该方程中各项的系数a,b,c,d
输出格式:由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。
输入示例:1 -5 -4 20
输出示例:-2.00 2.00 5.00
【分析】
如果精确到小数点后两位,可用简单的枚举法:
将x从-100.00到100.00(步长为0.01)逐一枚举,得到20000个f(x),取其值与0最接近的三个f(x),对应的即为答案。
而题目已改成精度为小数点后4位,枚举算法肯定会超时。
直接利用求根公式,极为复杂。
我们想到二分法:利用二分法逐步缩小根的范围,从而得到根的某精度的数值。
当已知区间(a,b)内有一个根时,用二分法求根。
若区间(a,b)内有根,则必有f(a)*f(b)<0。重复执行下面的过程:
(1)若f((a+b)/2)=0或a+0.0001>b ,则可确定根为(a+b)/2并退出过程;
(2)若f(a)*f((a+b)/2)<0,由零点定理可知根在区间(a,(a+b)/2)中,则对区间重复该过程;
(3)若f(a)*f((a+b)/2)>0,则必有f((a+b)/2)*f(b)<0,则根在((a+b)/2,b)中,则对该区间重复该过程。
执行完毕,输出根。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
double a,b,c,d,ans[3];
int n=0;
double cal(double x){
return x*x*x*a+x*x*b+x*c+d;
}
void fz(double l,double r){
if(cal(l)*cal(r)>0&&((r-l)<1||n>=2)) return ;
double mid=(l+r)/2;
if(abs(cal(mid))<=1e-5){
ans[n++]=mid;
return ;
}
fz(l,mid);
fz(mid,r);
}
int main(){
cin>>a>>b>>c>>d;
fz(-100,100);
printf("%.2f %.2f %.2f",ans[0],ans[1],ans[2]);
return 0;
}