网址如下:P1024 [NOIP2001 提高组] 一元三次方程求解 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
做的还是比较顺利的,打草稿就是好
代码如下:
#include<stdio.h>
#include<math.h>
void dg(double l, double u);//下限 上限
double fx(double x);//f(x)函数
const double EPS = 1e-6, CMP = 1e-2;
double a, b, c, d, result[3];
int count;//目前找到的个数
int main(void)
{
//输入
scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
//处理在最左边的情况
double tmp = fx(-100.000);
if(fabs(tmp) < EPS) result[count++] = -100.000;
//开始遍历
for(double i = -100.000; 100.000 - i > EPS; i += 1.000)
{
double j = fx(i + 1.000);
//处理零点为整数的情况
if(fabs(j) < EPS)
{
result[count++] = i + 1.000, tmp = j;
continue;
}
//判断根是否在这个小范围内
if(fabs(tmp * j) > EPS && tmp * j < 0.0)
dg(i, i + 1.000);
//求完直接跳出循环
if(count == 3) break;
//更新tmp
tmp = j;
}
//输出
for(int i = 0; i < 3; i++)
{
if(i) putchar(' ');
printf("%.2f", result[i]);
}
return 0;
}
void dg(double l, double u)
{
double mid = (l + u) / 2;
double f_mid = fx(mid), f_l = fx(l);
//递归结束的条件
if(fabs(f_mid) < EPS || u - l < CMP)
{
result[count++] = mid;
return;
}
//下一区间
if(f_mid * f_l < 0.0) dg(l, mid);
else dg(mid, u);
return;
}
double fx(double x)
{
return a * pow(x, 3.0) + b * pow(x, 2.0) + c * x + d;
}
小小的解析:
里面的常数浮点数基本是精确到小数点后三位,是为了防止零点在区间边界上,而且因为浮点数误差,四舍五入的时候多了0.1的情况(虽然我不清楚误差会长什么样,但是使程序有更多的鲁棒性还是好的)
本来我是想要解决,如何在一个区间(-100,100)之间找到三个根(方法肯定是二分法了),但是,我看到了根的距离必定大于1,那么我就把这个区间分为200个长度为1的区间,这样就好做了,因为保证了一个区间只有一个根,那么就是标准的二分法
中途还是有些缺漏的,比如忘记更新tmp值,还有递归函数中用l * f_mid来判断下一步递归的情况(应该是f_l * f_mid的)
但是比起之前没打草稿,这一次顺畅了许多,思路也非常清晰