洛谷P1024 [NOIP2001 提高组] 一元三次方程求解(优雅的暴力+二分,干净利落)

编程入门 行业动态 更新时间:2024-10-06 14:33:08

洛谷P1024 [NOIP2001 提高组] 一元三次<a href=https://www.elefans.com/category/jswz/34/1766651.html style=方程求解(优雅的暴力+二分,干净利落)"/>

洛谷P1024 [NOIP2001 提高组] 一元三次方程求解(优雅的暴力+二分,干净利落)

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

  • 前言
  • 题目
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 题目分析
    • 注意事项
  • 代码
  • 后话
    • 额外测试用例
      • 样例输入 #2
      • 样例输出 #2
    • 王婆卖瓜
  • 题目来源

前言

没有前言,可能因为作者忘了编辑

题目

题目描述

有形如: a x 3 + b x 2 + c x + d = 0 a x^3 + b x^2 + c x + d = 0 ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数( a , b , c , d a,b,c,d a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在 − 100 -100 −100 至 100 100 100 之间),且根与根之差的绝对值 ≥ 1 \ge 1 ≥1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 2 2 2 位。

提示:记方程 f ( x ) = 0 f(x) = 0 f(x)=0,若存在 2 2 2 个数 x 1 x_1 x1​ 和 x 2 x_2 x2​,且 x 1 < x 2 x_1 < x_2 x1​<x2​, f ( x 1 ) × f ( x 2 ) < 0 f(x_1) \times f(x_2) < 0 f(x1​)×f(x2​)<0,则在 ( x 1 , x 2 ) (x_1, x_2) (x1​,x2​) 之间一定有一个根。

输入格式

一行, 4 4 4 个实数 a , b , c , d a, b, c, d a,b,c,d。

输出格式

一行, 3 3 3 个实根,从小到大输出,并精确到小数点后 2 2 2 位。

样例 #1

样例输入 #1

1 -5 -4 20

样例输出 #1

-2.00 2.00 5.00

题目分析

  这题就算比较简单的一题,也有很多方法,有数学加成比较高的盛金法牛顿迭代法等等,我就用比较简单易懂的暴力+二分来做。
  当然有个前提是知道勘根定理,当然题目也有给。就是记方程 f ( x ) = 0 f(x) = 0 f(x)=0,若存在 2 2 2 个数 x 1 x_1 x1​ 和 x 2 x_2 x2​,且 x 1 < x 2 x_1 < x_2 x1​<x2​, f ( x 1 ) × f ( x 2 ) < 0 f(x_1) \times f(x_2) < 0 f(x1​)×f(x2​)<0,则在 ( x 1 , x 2 ) (x_1, x_2) (x1​,x2​) 之间一定有一个根。
  能使用我这个方法也有一个前提就是题目所说的“两个根之间距离大于等于1” 。所以我们可以先间隔为1遍历每个长度为1的区间,只需要200次就可以找到三个解的大致区间。
然后就剩下三个分别为1 的区间是解,这是我们就可以用二分的方法利用勘根定理来做二分,只要l和mid的符号相同(相乘为正)说明不在这个区间内,我们就可以更换区间,知道l逼近于r,这时候就不需要考虑这个区间中有几个解。

注意事项

1.注意浮点数的处理,建议里面都使用浮点数,使用int可能会损失精度。
2.浮点数关于相等的判断。使用fabs(x)<1e-6或者x<1e-6&&x>1e-6来判断x是否等于0,使用l-r<1e-6来判断l==r
3.关于有解等于0的办法。我这里将符合的解都加上0.001,这样就不会出现等于0导致误判的情况了。

代码

轻松拿下,只有四个点。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;double a,b,c,d;
double f(double x){//函数值return a*x*x*x+b*x*x+c*x+d;
}
int negative(double x){//返回正负性或0if(fabs(x)<=1e-6){return 0;}else if(x<0){return -1;		}elsereturn 1;
}
int main()
{cin>> a>>b>>c>>d;double solution[100]={0};int point =0;double lastsol=negative(f(-100));for(int i=-99;i<=100;i++){if(f(i)*lastsol<=0||fabs(f(i))<1e-6)solution[point++]=i+0.001;lastsol=negative(f(i+0.001));}for(int i =0;i<3;i++){double l=solution[i]-1,r=solution[i]+1;while(r-l>0.001){double mid = (l+r)/2;if(f(l)*f(mid)>0)//说明l和mid在同侧,则解在mid和r之间l=mid;elser=mid; 	}printf("%.2lf ",(l+r)/2); }return 0;
}

后话

额外测试用例

因为忘记考虑浮点数精度而获得了一个用例

样例输入 #2

1 -4.65 2.25 1.4

样例输出 #2

-0.35 1.00 4.00

王婆卖瓜

感觉有收获或者想跟上我的进度刷题的,可以点个关注,或者点赞收藏评论都可以!

题目来源

NOIP 2001 提高组第一题
洛谷链接

更多推荐

洛谷P1024 [NOIP2001 提高组] 一元三次方程求解(优雅的暴力+二分,干净利落)

本文发布于:2023-11-16 02:44:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1611770.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:干净利落   方程   暴力   优雅   洛谷

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!