华师一附中OI组

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1242|回复: 2
打印 上一主题 下一主题

P1024 一元三次方程求解

[复制链接]

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
跳转到指定楼层
楼主
发表于 2018-4-14 20:37:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。

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

【思路】此题本是求方程的解,可以用求根公式,不过相信绝大多数的高中生都不知道,(我曾经记得,不过现在也忘记了)但是此题设置了很多的条件,根的范围,根的距离,还有提示,这就告诉我们,可以使用二分法。二分的要素是单调性和起点终点,此题似乎不满足,但是我们可以技巧性的处理一下:
1、        根与根的差的绝对值>=1,所以我们可以列举-100到100之间的所有整数点,碰到整数点对应的F(x)为零,说明找到一个根,若F(x)* F(x+1)<0,说明(x1,x2)之间一定有一个根
2、        二分x和x+1,按照我讲的带精度的二分,分成两种情况,增函数和减函数的做法

要是你觉得写不出来,还有一个做法,就是-100到100之间分成200*1000个点,按顺序枚举所有的点,f(x)=0的地方输出,这样写我好像得了40分。

【程序】
用eps表示精度要求,初始设置为0,0001,对于保留两位小数而言是足够了。
用a[3]表示三个根
  1. #include<iostream>
  2. #include<iomanip>
  3. #include<cmath>
  4. using namespace std;
  5. double eps=0.0001;
  6. int i,j;
  7. double A,B,C,D;
  8. double x;
  9. double a[3];
  10. double l,r,m;
  11. bool b;
  12. double f(double x)
  13. {
  14.     return A*x*x*x+B*x*x+C*x+D;
  15. }
  16. int main()
  17. {
  18.     cin>>A>>B>>C>>D;
  19.     j=0;
  20.     for (i=-100; i<=100; i++)

  21.     {
  22.         x=double(i);
  23.         if (f(x)==0) a[j++]=x;      特殊判断,千万要不要忘记!!!
  24.         else if (f(x)<0 && f(x+1)>0)   diggersun的标准二分模板
  25.         {
  26.             l=x,r=x+1;
  27.             b=1;
  28.             while (l<=r && b)
  29.             {
  30.                  m=(l+r)/2;
  31.                 if ((f(m)==0) || (abs(l-r)<=eps)) b=0;

  32.                 else if (f(m)>0) r=m-eps;
  33.                 else l=m+eps;
  34.             }
  35.              if (b==0) a[j++]=m;
  36.         }
  37.         else if (f(x)>0 && f(x+1)<0)    两种情况
  38.         {
  39.             l=x,r=x+1;
  40.             b=1;
  41.             while (l<=r && b)
  42.             {
  43.                 m=(l+r)/2;
  44.                 if ((f(m)==0) || (abs(l-r)<=eps)) b=0;

  45.                 else if (f(m)<0) r=m-eps;
  46.                 else l=m+eps;
  47.             }
  48.              if (b==0) a[j++]=m;
  49.         }

  50.     }


  51.     for (i=0; i<=2; i++)
  52.         cout<<fixed<<setprecision(2)<<a[i]<<' ';    保留两位小数的输出技巧
  53.     return 0;
  54. }
复制代码
回复

使用道具 举报

2

主题

105

帖子

306

积分

中级会员

Rank: 3Rank: 3

积分
306
沙发
发表于 2018-7-29 23:59:11 | 只看该作者
  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <iostream>
  4. #include <cmath>
  5. #include <cstring>
  6. using namespace std;
  7. double a,b,c,d;
  8. bool check(double x)
  9. {
  10.         double s=a*x*x*x+b*x*x+c*x+d;
  11.         if(s>=-0.01&&s<=0.01)
  12.                 return true;
  13.         return false;
  14. }
  15. int main()
  16. {
  17.         scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
  18.         int n=0;
  19.         for(double i=-100.00;i<=100.00;i+=0.001)
  20.         {
  21.                 if(check(i))
  22.                 {
  23.                         n++;
  24.                         printf("%.2lf ",i);
  25.                         i+=0.999;
  26.                 }       
  27.                 if(n==3)
  28.                         break;
  29.         }
  30.         return 0;
  31. }
复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|服务支持:DZ动力|华师一附中OI组  

GMT+8, 2024-12-26 02:23 , Processed in 0.096914 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表