【分治】一元三次方程求解

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求三个实根。
输入
四个实数:a,b,c,d
输出
由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位
样例输入 Copy
1 -5 -4 20
样例输出 Copy
-2.00 2.00 5.00
提示
数据规模和约定
|a|,|b|,|c|,|d|<=10
题解:
由题意知方程一定有3个不同的实根,根据数学知识,对应的三次函数的图像一定是增-减-增或者减-增-减两种可能。不妨讨论增-减-增的情况:易知图像在每个单调区间内都有一个实数根,可以在每个单调区间上利用二分法求解对应的一个实数根(这里体现了分治的思想),而单调区间的分界点就是2个极值点,可以通过求导、解一元二次方程、代入求根公式求得。减-增-减对应的情况类似。

需要注意的几个细节:
1.需要对a的正负进行讨论,a>0时图像增-减-增,a<0时图像减-增-减。
2.a的正负对两个极值点的横坐标的大小关系有影响(会影响到二分时的左右端点的确定,具体可比较代码),可以通过代入具体的值+printf()语句来判断。
3.第一个区间的左端点值和最后一个区间的右端点值不是无穷,根据题意可以分别取成-200和200。
4.高一数学学过二分法求方程的近似解,根据区间中点横坐标对应的函数值与0的关系来决定取哪一部分区间(二分法的基本思想),同时还要注意区间的增减性对选择区间的影响,代码中对其作出了讨论。
5.实数的二分法,一是注意左右端点的移动,直接令l=midr=mid,最后输出l,r其中之一,二是注意循环进行的条件:l+eps<r,这里的eps一般要比题中要求的精度(1e-2)多两位。
6.可以利用matlab求解一元三次方程,根据matlab求解的结果验证程序的正确性。首先建立m文件,然后在m文件中输入roots([a b c d]),点击运行后命令行窗口输出对应的3个解,这里的a,b,c,d可以为小数,也可以为整数,数字之间有空格,输入的4个数一定要满足有3个符合题意的实数解。

输入:roots([-1.5 4.2 8.9 -3.4])
命令行运行结果:
ans = 4.1096 -1.6449 0.3353
程序运行结果:

-1.5 4.2 8.9 -3.4 
-1.64 0.34 4.11
Process returned 0 (0x0)   execution time : 1.825 s
Press any key to continue.

AC代码:

#include<stdio.h>
#include<math.h>
#define eps 1e-4
const double INF_MIN=-200;
const double INF_MAX=200;
int main()
{ 
    double a;
    double b;
    double c;
    double d;
    double x_01;
    double x_02;
    double l;
    double r;
    double mid;
    scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
    x_01=(-b-sqrt(b*b-3*a*c))/(3*a);
    x_02=(-b+sqrt(b*b-3*a*c))/(3*a);
    //printf("x_01=%.2f,x_02=%.2f\n",x_01,x_02);用于判断2个极值点横坐标的大小关系
    if(a>0)
    { 
        l=INF_MIN;
        r=x_01;
        while(l+eps<r)//循环条件
        { 
            mid=(l+r)/2;
            if(a*mid*mid*mid+b*mid*mid+c*mid+d<0)l=mid;
            else r=mid;
        }
        printf("%.2f ",l);
        l=x_01;
        r=x_02;
        while(l+eps<r)
        { 
            mid=(l+r)/2;
            if(a*mid*mid*mid+b*mid*mid+c*mid+d<0)r=mid;
            else l=mid;
        }
        printf("%.2f ",l);
        l=x_02;
        r=INF_MAX;
        while(l+eps<r)
        { 
            mid=(l+r)/2;
            if(a*mid*mid*mid+b*mid*mid+c*mid+d<0)l=mid;
            else r=mid;
        }
        printf("%.2f",l);
    }
    else if(a<0)
    { 
        l=INF_MIN;
        r=x_02;
        while(l+eps<r)
        { 
            mid=(l+r)/2;
            if(a*mid*mid*mid+b*mid*mid+c*mid+d<0)r=mid;
            else l=mid;
        }
        printf("%.2f ",l);
        l=x_02;
        r=x_01;
        while(l+eps<r)
        { 
            mid=(l+r)/2;
            if(a*mid*mid*mid+b*mid*mid+c*mid+d<0)l=mid;
            else r=mid;
        }
        printf("%.2f ",l);
        l=x_01;
        r=INF_MAX;
        while(l+eps<r)
        { 
            mid=(l+r)/2;
            if(a*mid*mid*mid+b*mid*mid+c*mid+d<0)r=mid;
            else l=mid;
        }
        printf("%.2f",l);
    }
    return 0;
}
    原文作者:Master.Jiang
    原文地址: https://blog.csdn.net/upc122/article/details/104336336
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞