信息学奥赛一本通 1238:一元三次方程求解 | 1824 | OpenJudge NOI 2.4 7891 | 洛谷 P1024 [NOIP2001 提高组] 一元三次方程求解

【题目链接】

ybt 1238:一元三次方程求解
ybt 1824:【01NOIP提高组】一元三次方程求解
OpenJudge NOI 2.4 7891:一元三次方程求解
洛谷 P1024 [NOIP2001 提高组] 一元三次方程求解

【题目考点】

1. 二分:实数域二分查找
  • 实数域二分查找
    二分求函数零点问题,即为实数域上的二分查找。
    代码模板为:
while(r - l >= 1e-x)//保留到小数点后x+1位
{
	double mid = (l+r)/2;
	if(要查找的结果小于m)
		r = m;
	else
		l = m;
}

【解题思路】

1. 二分:实数域二分查找

已知方程: a x 3 + b x 2 + c x + d = 0 ax^3+bx^2+cx+d=0 ax3+bx2+cx+d=0
记函数 f ( x ) = a x 3 + b x 2 + c x + d f(x)=ax^3+bx^2+cx+d f(x)=ax3+bx2+cx+d,该方程的根即为函数 f ( x ) f(x) f(x)的零点。
已知根与根绝对值之差大于等于1,如果 x 2 − x 1 = 1 x_2-x_1 = 1 x2x1=1,那么在长为1的跨度内,有以下几种情况:

  • 如果 f ( x 1 ) ∗ f ( x 2 ) = 0 f(x_1)*f(x_2) = 0 f(x1)f(x2)=0,那么 x 1 x_1 x1是零点或 x 2 x_2 x2零点,也可能二者都是零点。
  • 如果 f ( x 1 ) ∗ f ( x 2 ) < 0 f(x_1)*f(x_2) < 0 f(x1)f(x2)<0,那么 x 1 x_1 x1 x 2 x_2 x2之间只有1个零点。(因为根与根绝对值之差大于等于1,所以在跨度为1的范围内不可能有3个零点)
  • 如果 f ( x 1 ) ∗ f ( x 2 ) > 0 f(x_1)*f(x_2) > 0 f(x1)f(x2)>0,那么 x 1 x_1 x1 x 2 x_2 x2之间没有零点。

遍历根存在的范围 − 100 ∼ 100 -100\sim 100 100100,每次取跨度为1的区间。设区间左端点为 x 1 x_1 x1,右端点为 x 2 x_2 x2

  • 如果 f ( x 1 ) = 0 f(x_1)=0 f(x1)=0,那么 x 1 x_1 x1就是零点。

  • 如果 f ( x 1 ) ∗ f ( x 2 ) < 0 f(x_1)*f(x_2) < 0 f(x1)f(x2)<0,那么 x 1 x_1 x1 x 2 x_2 x2之间只有1个零点。通过实数域二分查找方法找到该区间内的零点。
    二分查找区间 l = x 1 , r = x 2 l=x_1, r=x_2 l=x1,r=x2,取m为区间中点 m = ( l + r ) / 2 m=(l+r)/2 m=(l+r)/2

    • 如果 f ( l ) ∗ f ( m ) > 0 f(l)*f(m) > 0 f(l)f(m)>0,说明左半边没有零点,零点在右半边,应该让 l = m l=m l=m
    • 如果 f ( l ) ∗ f ( m ) < 0 f(l)*f(m) < 0 f(l)f(m)<0,说明左半边有零点,应该让 r = m r = m r=m
    • 如果 f ( l ) ∗ f ( m ) = 0 f(l)*f(m) = 0 f(l)f(m)=0,说明m就是零点。

    二分查找直到满足精度,而后输出m。

  • 如果 f ( x 1 ) ∗ f ( x 2 ) > 0 f(x_1)*f(x_2) >0 f(x1)f(x2)>0,那么 x 1 x_1 x1 x 2 x_2 x2之间没有零点,略过。

【题解代码】

解法1:二分:实数域二分查找
#include<bits/stdc++.h>
using namespace std;
double a, b, c, d;
double f(double x)//求方程的跟,即为求f(x)的零点 
{
    return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
    double x1, x2, l , r, m;
    cin >> a >> b >> c >> d;
    for(int i = -100; i <= 100; ++i)//遍历整个区间 
    {
        x1 = i, x2 = i + 1;
        if(f(x1) == 0)
            cout << fixed << setprecision(2) << x1 << ' ';
        else if(f(x1) * f(x2) < 0)//x1到x2范围内有零点 
        {
            l = x1, r = x2;
            while(r - l >= 1e-3)//保留到小数点后2位 
            {
                m = (l + r) / 2;
                if(f(m) * f(l) > 0)
                    l = m;
                else if(f(m) * f(l) < 0)
                    r = m;
                else
                    break;
            }
            cout << fixed << setprecision(2) << m << ' '; 
        }
    }
    return 0;
}
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值