题目描述

有形如:ax^3+bx^2+cx^1+dx^0=0ax3+bx2+cx1+dx0=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,da,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在-100100至100100之间),且根与根之差的绝对值\ge 11。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后22位。

提示:记方程f(x)=0f(x)=0,若存在22个数x_1x1x_2x2,且x_1<x_2x1<x2f(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:二分

如果不会公式,可以根据题意:(根的范围在-100100至100100之间),且根与根之差的绝对值\ge 11,边枚举,边二分。

#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;
}