【二分】一元三次方程扩展

【二分】一元三次方程扩展

题目描述

众所周知,巨佬是不屑于做水题的,所以这么水的题只有交给你来完成啦。

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

输入输出格式

  • 输入格式:
    一行,4个实数A,B,C,D。
  • 输出格式:
    一行,三个实根,并精确到小数点后2位。

观察可发现本题的数据范围和精度其小无比,-100到100,精度小数点后两位,
就算是0.01 0.01的枚举也不过是O(20000)的复杂度,完全可以接受。

于是有此暴力代码。。

#include<stdio.h>
double a,b,c,d;
int main()
{ 
    scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
    for(double i=-100.00;i<=100.00;i+=0.01)
    {
        if(a*i*i*i+b*i*i+c*i+d<0.00000001&&a*i*i*i+b*i*i+c*i+d>-0.00000001)
        //注意判断浮点误差,一般认为答案差值不超过0.00000001为正确
            printf("%.2f ",i);
    }
    return 0;
}

思考

此题极具特殊性,如果没有精度和范围的限制,又该如何求解
对于在线性顺序排序的结构中,我们往往使用二分查找。
但此题有一点不同·
如图为一元三次函数的图像
这里写图片描述
因为其不具有单调性,所以要将其分为三段依次求每段上的根。
列如此图可分为(-∞,-2)(2,1)(1,+∞)三段,再分别在每一段上二分查找。
那么问题也就转化为了如何寻找斜率为0的两个点的问题,对于此问题可以对原三次函数进行求导,求解一元二次的导函数得到分界点的值分别为x1,x2.
于是就可以分别为(-∞,x1)(x1,x2)(x2,+∞)三段上依次求解。

代码

#include<math.h>
#include<stdio.h>
double esp=1e-4;
int a,b,c,d;
int check(double x)
{
    return a*x*x*x+b*x*x+c*x+d>0?1:0; 
}
double find (double l,double r)
{
    double temp=(l+r)/2;
    while(r-l>=esp)
    {
        if(check(temp)+check(l)==0||check(temp)+check(l)==2)
        {
            l=temp;
        }
        else
        r=temp;
        temp=(l+r)/2;
    }
    return r;
}
int main()
{
    scanf("%d %d %d %d",&a,&b,&c,&d);
    double x1,x2,t;
    double data=pow((4*b*b-12*a*c),0.5);
    x1=(-2*b+data)/6/a;
    x2=(-2*b-data)/6/a;//计算x1,x2。
    if(x1>x2)
    {
        t=x1;
        x1=x2;
        x2=t;
    }//判断x1,x2的大小关系,把小的放在x1.
    double ans1=find(-100.0,x1);
    double ans2=find(x1,x2);
    double ans3=find(x2,100.0);
    printf("%.2lf %.2lf %.2lf",ans1,ans2,ans3);
    return 0;
}

后记

我还是太弱了,明明有公式还要硬算,算是被完爆了,
附一元三次方程求根公式
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_40355973/article/details/80449869