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

P1024 [NOIP2001 提高组] 一元三次方程求解_第1张图片

网址如下:P1024 [NOIP2001 提高组] 一元三次方程求解 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

做的还是比较顺利的,打草稿就是好

代码如下:

#include
#include
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的)

但是比起之前没打草稿,这一次顺畅了许多,思路也非常清晰

你可能感兴趣的:(算法)