洛谷 P1024 一元三次方程求解 二分 枚举

洛谷 P1024 一元三次方程求解 二分 枚举

https://www.luogu.com.cn/problem/P1024

题目描述

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

提示:记方程f(x)=0,若存在2个数x1x2,且x1<x2,f(x1)×f(x2)<0,则在(x1,x2)之间一定有一个根。

输入格式

一行,4个实数A,B,C,D

输出格式

一行,3个实根,并精确到小数点后2位。

输入输出样例

输入 #1

1 -5 -4 20

输出 #1

-2.00 2.00 5.00

思路:

求出两个导数零点,将函数分成三个区域,每个区域中存在一个实根

对每个区域进行二分查找

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const long long mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const double PI = 3.141592;
const int e = 1e-3;

double a, b, c, d;

double cal(double x){
    return a * x * x * x + b * x * x + c * x + d;
}

double tiwce(double l, double r){
    double ans = l;
    while(r - l > 1e-3){   //控制精度
        double mid = (r + l) / 2;
        if(cal(l) * cal(mid) < 0) r = mid;
        else l = mid;
        ans = mid;
    }
    return ans;
}

int main()
{
    scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
    double edg1, edg2;
    //求导数零点
    edg1 = (-2 * b + sqrt(4 * b * b - 12 * a * c)) / (6 * a);
    edg2 = (-2 * b - sqrt(4 * b * b - 12 * a * c)) / (6 * a);
    if(edg1 > edg2){
        double temp;
        temp = edg1;
        edg1 = edg2;
        edg2 = temp;
    }
    double ans[3];
    ans[0] = tiwce(-100, edg1);
    ans[1] = tiwce(edg1, edg2);
    ans[2] = tiwce(edg2, 100);
    sort(ans, ans + 3);
    printf("%.2f %.2f %.2f\n", ans[0], ans[1], ans[2]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章