UOJ Logo wbqyyds的博客

博客

「题解」P1024 一元三次方程求解

2023-01-16 12:19:35 By wbqyyds

题目传送门:一元三次方程求解

盛金公式

$part \texttt{1.}$ 基本概念

  • 根:方程的解。
  • 实根:指方程式的解为实数解。实数包括正数,负数和 $0$。

$part \texttt{2.}$ 一元三次方程的一般形式

$$ax^3+bx^2+cx+d=0\left(a\neq0\right).$$

$part \texttt{3.}$ 一元三次方程的实根

令 $x=y-\dfrac{b}{3a}$,则

$$a\left(y-\dfrac{b}{3a}\right)^3+b\left(y-\dfrac{b}{3a}\right)^2+c\left(y-\dfrac{b}{3a}\right)+d=0$$

$$a\left(y^3-\dfrac{by^2}{a}+\dfrac{b^2y}{3a^2}-\dfrac{b^3}{27a^3}\right)+b\left(y^2-\dfrac{2by}{3a}+\dfrac{b^2}{9a^2}\right)+c\left(y-\dfrac{b}{3a}\right)+d=0$$

$$ay^3-by^2+\dfrac{b^2}{3a}y-\dfrac{b^3}{27a^2}+by^2-\dfrac{2b^2}{3a}y+\dfrac{b^3}{9a^2}+cy-\dfrac{bc}{3a}+d=0$$

$$ay^3+\left(c-\dfrac{b^2}{3a}\right)y+\left(d+\dfrac{2b^3}{27a^2}-\dfrac{bc}{3a}\right)=0$$

$$y^3+\left(\dfrac{c}{a}-\dfrac{b^2}{3a^2}\right)y+\left(\dfrac{d}{a}+\dfrac{2b^3}{27a^3}-\dfrac{bc}{3a^2}\right)=0$$

令 $p=\dfrac{c}{3a}-\dfrac{b^2}{9a^2}$,$q=\dfrac{d}{2a}+\dfrac{b^3}{27a^3}-\dfrac{bc}{6a^2}$,则

$$y^3+3py+2q=0$$

令 $\Delta=q^2+p^3$,则

$\left(1\right)$ 当 $\Delta>0$ 时,方程只有一个实根:

$$y=\sqrt[3]{-q+\sqrt{\Delta}}+\sqrt[3]{-q-\sqrt{\Delta}}$$

$\left(2\right)$ 当 $\Delta=0$ 时,方程有三个实根,其中至少有两个相等的实根:

$$y_1=-2\sqrt[3]{q}$$

$$y_2=y_3=\sqrt[3]{q}$$

$\left(3\right)$ 当 $\Delta<0$ 时,方程有三个不等实根:

$\quad \ \ $令 $\alpha=\dfrac{1}{3}\arccos\dfrac{-q\sqrt{-p}}{p^2}$,则

$$y_1=2\sqrt{-p}\cos\alpha$$

$$y_2=2\sqrt{-p}\cos\left(\alpha+120^\circ\right)$$

$$y_3=2\sqrt{-p}\cos\left(\alpha+240^\circ\right)$$

$part \texttt{4.}$ 代码实现

// 除一元三次方程外,附上一元一次方程与一元二次方程的实根求解代码
#include <bits/stdc++.h>
using namespace std;
// #define int long long

const double PIE = 3.1415926535897932384626433832795;
static double SolveCubicRoot(double value); // 立方根
static void SolveLinearEquation(double a, double b); // 一元一次方程
static void SolveQuadraticEquation(double a, double b, double c); // 一元二次方程
static void SolveCubicEquation(double a, double b, double c, double d); // 一元三次方程

int op;
double A, B, C, D;
vector<double> root;

// 求一个实数的立方根
double SolveCubicRoot(double value) {
    return value > 0 ? pow(value, 1.0 / 3) : -pow(-value, 1.0 / 3);
}

// 求一元一次方程的实根
void SolveLinearEquation(double a, double b) {
    if (a != 0) // 判断一次项系数是否为零
        root.push_back(-b / a);
    return;
}

// 求一元二次方程的实根
void SolveQuadraticEquation(double a, double b, double c) {
    if (a == 0) { // 判断二次项系数是否为零
        SolveLinearEquation(b, c);
        return;
    }
    double delta = b * b - 4 * a * c; // 判别式
    if (delta > 0) { // 方程有两个不等的实根
        root.push_back((-b + sqrt(delta)) / (2 * a));
        root.push_back((-b - sqrt(delta)) / (2 * a));
    } else if (delta == 0) // 方程有两个相等的实根
        root.push_back(-b / (2 * a));
    return;
}

// 求一元三次方程的实根
void SolveCubicEquation(double a, double b, double c, double d) {
    if (a == 0) { // 判断三次项系数是否为零
        SolveQuadraticEquation(b, c, d);
        return;
    }
    double p = (c / a - b * b / (3 * a * a)) / 3;
    double q = (d / a + 2 * b * b * b / (27 * a * a * a) - b * c / (3 * a * a)) / 2;
    double diff = -b / (3 * a);
    double delta = p * p * p + q * q; // 判别式
    if (delta > 0) { // 方程只有一个实根
        double sqrtDelta = sqrt(delta);
        root.push_back(SolveCubicRoot(-q + sqrtDelta) + SolveCubicRoot(-q - sqrtDelta));
    } else if (delta < 0) { // 方程有三个不等的实根
        double angle = acos(-q * sqrt(-p) / (p * p)) / 3;
        root.push_back(2.0 * sqrt(-p) * cos(angle));
        root.push_back(2.0 * sqrt(-p) * cos(angle + 2 * PIE / 3));
        root.push_back(2.0 * sqrt(-p) * cos(angle + 4 * PIE / 3));
    } else { // 方程有三个实根,其中至少有两个相等的实根
        if (q == 0) root.push_back(0);
        else {
            root.push_back(SolveCubicRoot(q));
            root.push_back(-2 * SolveCubicRoot(q));
        }
    }
    for (int i = 0, maxSize = root.size(); i < maxSize; ++i)
        root[i] += diff; // 将结果加上余量
    return;
}

// 排序并打印结果
void print() {
    priority_queue<double, vector<double>, greater<double> > q;
    int cnt = 0;
    for (auto i : root) {
        q.push(i);
        cnt++;
    }
    while (cnt--) {
        cout << fixed << setprecision(2) << q.top() << " ";
        // 保留两位小数,也可以用 printf 的 %.2f
        q.pop(); // 记住一定要 pop
    }
    cout << "\n";
}

signed main() {
    cin >> op;
    if (op == 1) { // 一元一次方程
        cin >> A >> B;
        SolveLinearEquation(A, B);
        print();
    } else if (op == 2) { // 一元二次方程
        cin >> A >> B >> C;
        SolveQuadraticEquation(A, B, C);
        print();
    } else { // 一元三次方程
        cin >> A >> B >> C >> D;
        SolveCubicEquation(A, B, C, D);
        print();
    }
    return 0;
}
正解提交结果

代码不是题目的正解,会有小改动,学习后自己敲哦

PS: 如有错误请在聊天区 @ 我哦

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。