洛谷-P1024 [NOIP2001 提高组] 一元三次方程求解

  题目描述

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

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

  输入格式

一行,44 个实数 a, b, c, d。

  输出格式

一行,33 个实根,从小到大输出,并精确到小数点后 22 位。

  输入输出样例

输入#1

输出#1

1 -5 -4 20

-2.00 2.00 5.00

  题目分析

  1. 方程求解时,计算机一般采用二分法去不断逼近方程的解,当二分区间小于某个精度的时候我们就可以近似的认为该区间的中间值为方程的解。
  2. 根据题目所给信息,三个根的范围一定是在(-100, 100),并且任意两个根的绝对值之差大于1,可知:根的总范围为(-100, 100)且最小寻找区间长度为1。我们只需要从-100开始以1为区间长度,不断判断区间内是否有根。
  3. 注意:二分查找时是否查每个小区间的边界,本文代码是查了双边界的,但是由于解如果在边界就会重复,注意去重。

  可行代码

#include <algorithm>
#include <iostream>
using namespace std;

double a, b, c, d;
double f(double x) { 
    return a * x * x * x + b * x * x + c * x + d; 
} // f(x)

double search(double l, double r) {
    double mid;
    bool flag = true;
    for (int i = 0; i <= 2000; i++) {
        mid = (l + r) / 2.0;
        if (f(l) * f(mid) <= 0)
            r = mid;
        else if (f(r) * f(mid) <= 0)
            l = mid;
        else {
            flag = false;// 查到结果直接返回
            break;
        }
    }
    if (flag)
        return mid;
    return -1000;// 根不在区间(l, r)
}

int main() {
    cin >> a >> b >> c >> d;
    double X[3];
    int cnt = 0;
    for (int i = -100; i <= 100; i++) {
        double x = search(i, i + 1);
        if (x != -1000 && X[0] != x && X[1] != x && X[2] != x)
            X[cnt++] = x;// 边界解会重复,去重
    }
    printf("%.2lf %.2lf %.2lf", X[0], X[1], X[2]);
    return 0;
}

END 感谢reader's阅读,洛谷题目链接:P1024 [NOIP2001 提高组] 一元三次方程求解 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

原文地址:https://www.cnblogs.com/kirk-notes/p/14994974.html