[NOIP2001 提高组] 一元三次方程求解

题目描述

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

提示:记方程 $f(x) = 0$,若存在 $2$ 个数 $x_1$ 和 $x_2$,且 $x_1 < x_2$,$f(x_1) \times f(x_2) < 0$,则在 $(x_1, x_2)$ 之间一定有一个根。

输入格式

一行,$4$ 个实数 $a, b, c, d$。

输出格式

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

样例 #1

样例输入 #1

1
1 -5 -4 20

样例输出 #1

1
-2.00 2.00 5.00

提示

【题目来源】
NOIP 2001 提高组第一题

题解

  • 注意到题目
  • 提示:记方程 $f(x) = 0$,若存在 $2$ 个数 $x_1$ 和 $x_2$,且 $x_1 < x_2$,$f(x_1) \times f(x_2) < 0$,则在 $(x_1, x_2)$ 之间一定有一个根。
  • 那么说明可能最左侧是一个根
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class Main {

static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

static double nextDouble() throws IOException {
st.nextToken();
return st.nval;
}


static double check(double x) {
// 原式子
// 等于0 就是这个方程的解
return a * x * x * x + b * x * x + c * x + d;
}

static double a;
static double b;
static double c;
static double d;

public static void main(String[] args) throws IOException {
a = nextDouble();
b = nextDouble();
c = nextDouble();
d = nextDouble();

for (int i = -100; i < 100; i++) {
// 一个数一个数的找
double l = i;
double r = i + 1d;

// 提示中
// x1 · x2 < 0 x1 x2有根
if (check(l) * check(r) < 0) {
// 用二分查找他之间的解
while (r - l >= 0.001d) {// 精度0.01不够
double mid = (r + l) / 2;
// x1 · x2 < 0 x1 x2有根
if (check(mid) * check(r) < 0) {
// 缩减左端点
l = mid;
} else {
// 缩减右端点
r = mid;
}
}
System.out.printf("%.2f ", r);
} else if (check(l) == 0) {
// 只输出左点
// 上方的二分包括了右端点
System.out.printf("%.2f ", l);
}
}
}

}