★P1024 [NOIP 2001 提高组] 一元三次方程求解
题目描述
有形如:\(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 -5 -4 20
输出 #1
-2.00 2.00 5.00
说明/提示
【题目来源】
NOIP 2001 提高组第一题
题解
#include <bits/stdc++.h>
using namespace std;
double a, b, c, d;
vector<double> roots;
double f(double x) {
return a*x*x*x + b*x*x + c*x + d;
}
// 本题有一个测试点会重复计入根,当一个端点(例如 i 或 i+1)正好满足 f(x) ≈ 0 时,代码会先直接把这个端点加入根列表;随后在同一个区间,二分法又找到了一个近似相同的根,导致重复计入,这里添加判断防止重复,在每次加入新根前,可以判断当前新根与已存在根的距离是否足够大(如大于 1e-6),如果非常接近则跳过。
bool isNewRoot(double x) {
for (double r : roots) {
if (fabs(r - x) < 1e-6)
return false;
}
return true;
}
void search() {
for (double i = -100; i < 100; i++) {
double left = i, right = i + 1;
// 判断端点是否为根
if (fabs(f(left)) < 1e-6 && isNewRoot(left)) {
roots.push_back(left);
if (roots.size() == 3) break;
continue; // 跳过本次区间的二分,防止重复计入
}
if (fabs(f(right)) < 1e-6 && isNewRoot(right)) {
// 如果右端点是根,先尝试二分法,避免重复
if (f(left)*f(right) < 0) {
// 二分求根
while (right - left > 1e-7) {
double mid = left + (right - left) / 2;
if (f(mid) * f(left) < 0)
right = mid;
else
left = mid;
}
double root = (left + right) / 2;
if (isNewRoot(root)) {
roots.push_back(root);
if (roots.size() == 3) break;
}
} else {
// 如果区间内没有符号变化,则直接添加右端点
roots.push_back(right);
if (roots.size() == 3) break;
continue;
}
}
// 对于一般情况,判断区间内是否有根
if (f(left) * f(right) < 0) {
while (right - left > 1e-7) {
double mid = left + (right - left) / 2;
if (f(mid) * f(left) < 0)
right = mid;
else
left = mid;
}
double root = (left + right) / 2;
if (isNewRoot(root)) {
roots.push_back(root);
if (roots.size() == 3) break;
}
}
}
}
int main() {
cin >> a >> b >> c >> d;
search();
sort(roots.begin(), roots.end());
for (size_t i = 0; i < roots.size(); i++) {
if (i > 0) cout << " ";
printf("%.2lf", roots[i]);
}
cout << endl;
return 0;
}
浙公网安备 33010602011771号