题目描述
有形如:ax^3+bx^2+cx^1+dx^0=0ax3+bx2+cx1+dx0=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
解析1:暴力枚举(暴力出奇迹)
因为解的取值范围(-100~100),结果保留小数点后2位,完全可以枚举解决。需要注意的是,只有满足以下条件,才能确定解:
double l=i,r=i+0.001;
if((a*l*l*l+b*l*l+c*l+d)*(a*r*r*r+b*r*r+c*r+d)<0){
printf("%.2lf ",l);
而不能直接
a*l*l*l+b*l*l+c*l+d=0,实数因为精度问题,结果未必能直接等于0
#include<iostream> #include<cstdio> using namespace std; int main(){ double a,b,c,d; int num=0; cin>>a>>b>>c>>d; for(double i=-100.00;i<=100.00;i+=0.001){ double l=i,r=i+0.001; if((a*l*l*l+b*l*l+c*l+d)*(a*r*r*r+b*r*r+c*r+d)<0){// 若存在两个数x1,x2且x1<x2,f(x1)*f(x2)<0 则方程解肯定在x1~x2范围内 printf("%.2lf ",l); num++;// 小数点后两位输出 if (num>=3)break;//找到3个解直接退出循环,提高时间复杂度。 } } return 0; }
解析2:二分
如果不会公式,可以根据题意:(根的范围在-100−100至100100之间),且根与根之差的绝对值\ge 1≥1,边枚举,边二分。
#include<iostream> #include<cstdio> using namespace std; const int maxn=50050; double a,b,c,d; double f(double x){ return a*x*x*x+b*x*x+c*x+d ; } int main(){ cin>>a>>b>>c>>d; for(int i=-100;i<100;i++) if (f(i)*f(i+1)<0){ double l=i,r=i+1,eps=1e-4,mid; for(int j=1;j<=100;j++){ mid=(l+r)/2; if(f(l)*f(mid)<=0) { r=mid; } else l=mid; } printf("%.2lf ",mid); } else if(f(i)==0) printf("%.2lf ",double(i)); return 0; }