洛谷 一元三次方程求解 二分答案

286 阅读3分钟

P1024 一元三次方程求解

1. 思路

  1. 这题看分组是二分求解,然而这个题的二分不是普通的二分,因为有三个答案,所以需要把数据分段,至于怎么分,重点在且根与根之差的绝对值≥1 这句话,我们以1为长度,把-100到100看作200段,然后每段使用二分

    for(int i=-100;i<100;i++){
            double res = check(i,i+1);
    }
    
  2. 当且仅当x1<x2,f(x_1)* f(x_2)<0的时候存在解,那么这个就是我们check函数

    inline double fun(double x){
        return a*x*x*x+b*x*x+c*x+d;
    }
    if(fun(l)*fun(mid)>0)
            l = mid;
        else
            r = mid;
    
  3. 这题有个大问题,那就是如果不加限制的话,右节点是会访问两次的,比如当i是-100时,我们会检查一遍-100和-99,但是当i是-99时,我们又会访问一遍-99和-98,而-99就访问了两次,如果恰巧-99就是一个解的话,那么这个解我们会得到两次,从而影响正确结果

    我最初的做法是,把右节点左移0.0001,由于我们的精度要求是0.001,那么移动0.0001应该没什么问题,当然,最后还是证明有问题

    最终的解决办法是:先特判左节点为正确答案,然后返回之后再特判返回值是不是右节点,(有点复杂,但是我缺一个他就报错...,那位大牛帮忙指出下...QAQ)

    注水代码

    #include<iostream>
    #include<cmath>
    
    using namespace std;
    
    double a,b,c,d;
    inline double fun(double x){
        return a*x*x*x+b*x*x+c*x+d;
    }
    
    double check(double l,double r){
        double mid;
        if(fabs(fun(l)-0)<1e-8)return l;
        if(fun(l)*fun(r)>0)return -111;
        while(r-l>0.001){
            mid = (l+r)/2;
            if(fun(l)*fun(mid)>0)
                l = mid;
            else
                r = mid;
        }
        return l;
    }
    
    //-0.35 1.00 4.00
    int main(){
        freopen("data.in","r",stdin);
        cin>>a>>b>>c>>d;
        int e = 0;
        for(int i=-100;i<100;i++){
            double res = check(i,i+1);
            if(fabs(res-(i+1))<0.001)continue;
            if(res!=-111){
                printf("%.2lf ",res);
                if(++e==3)break;
            }
        }
    
        return 0;
    }
    

题面:

题目描述

有形如:ax^3+bx^2+cx^1+dx^0=0a**x3+b**x2+c**x1+d**x0=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