20241029每日一题洛谷P1024
普及-每日一题洛谷P1024
有形如:\(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 -5 -4 20
样例输出
-2.00 2.00 5.00
经典的二分求值问题,这道题题目限制了根的范围:根与根之差的绝对值 \(\ge 1\) ,根的范围在 \(-100\) 至 \(100\) 之间
于是,我们的大致流程就是:
-
通过\(f(x_1) \times f(x_2) < 0\),寻找到一个区间\((x_1, x_2)\)使得其中必存在一个根
-
由于根与根之差的绝对值 \(\ge 1\) ,所以寻找区间时,可以以 \(1\) 作为一个跨度
-
再使用二分法,在含根区间内找到一个近似根
-
题目要求:精确到小数点后 \(2\) 位,这就存在两种找到根的途径:
-
二分的
mid
代入方程中,直接可解出 0 -
通过左边界
l
和右边界r
向根无限逼近,存在一个精度限制通过题目可知:精度需要在小数点后两位,所以在逼近根的时候,只需要控制左边界和右边界的差小于等于\(0.001\),
这时不妨举例有:\(l=1.005,r=1.006,root=1.00\) 任意选取
l或r
作为近似根,保留两位小数后,与根的大小几乎相同,可以认为找到了一个根
-
代码首先实现\(f(x)\)的操作:
double fx(double x) {
return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}
构建fx
函数,方便之后调用求值
然后实现在区间内寻找根的函数find
:
double find(double l, double r) {
while (r-l>0.001)//控制近似根的误差小于等于0.001
{
double mid = (l + r) / 2;
if (fx(l) * fx(mid) <= 0)
r = mid;
else
l = mid;
}
return l;//返回l或r都可以
}
最后执行在\([-100,100]\)之间寻找含根区间:
for (int i = -100; i <= 100; i++) {
double l = i, r = i + 1;
double x1 = fx(l), x2 = fx(r);
if (x1 == 0) {//判断端点值是否恰好为根
printf("%.2lf ", l);
cnt++;
continue;
}//只用判断左端点
if (x1 * x2 < 0) {
printf("%.2lf ", find(x1,x2));
cnt++;//记录根的个数
}
if (cnt == 3) return 0;//根全部解完后直接退出
}
完整AC代码:
double a, b, c, d;
double fx(double x) {
return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}
double find(double l, double r) {
while (r-l>0.001)
{
double mid = (l + r) / 2;
if (fx(l) * fx(mid) < 0)
r = mid;
else
l = mid;
}
return l;
}
int main()
{
scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
int cnt = 0;
for (int i = -100; i <= 100; i++) {
double l = i, r = i + 1;
double x1 = fx(l), x2 = fx(r);
if (x1 == 0) {
printf("%.2lf ", l);
cnt++;
continue;
}
if (x1 * x2 <= 0) {
printf("%.2lf ", find(x1,x2));
cnt++;
}
if (cnt == 3) return 0;
}
return 0;
}