一元三次方程求解(数学、二分)

https://www.luogu.com.cn/problem/P1024

Description

有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。

给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求三个实根。

Input

四个实数:a,b,c,d

Output

由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位

Sample Input

1 -5 -4 20

Sample Output

-2.00 2.00 5.00

HINT

数据规模和约定
|a|,|b|,|c|,|d|<=10

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

这题解法比较多

因为区间很大,所以可以二分。

题目保证三个答案都在[-100,100]范围内,且两个根的差的绝对值>=1,所以每一个大小为1的区间里至多有1个解。

当区间的两个端点的函数值异号时区间内一定有一个解,这个时候我们可以在区间内进行二分查找ans,如果同号则该区间一定没有解。

刚开始遍历i从-10000到10000了,然后i再除以100当成x的值,没想到这样显示TLE了。。。

 1 #include <stdio.h>
 2 #include <iostream>
 3 #include <string>
 4 #include <string.h>
 5 #include <algorithm>
 6 #include <map>
 7 #include <vector>
 8 #include <set>
 9 #include <stack>
10 #include <queue>
11 #include <math.h>
12 #include <sstream>
13 using namespace std;
14 typedef long long LL;
15 const int INF=0x3f3f3f3f;
16 const int maxn=1e5+10;
17 const double eps = 1e-8;
18 const double PI = acos(-1);
19
20 double a,b,c,d;//开成double吧,免得出错
21 vector<double> ans;
22 double f(double x)
23 {
24     return a*x*x*x+b*x*x+c*x+d;
25 }
26
27 double solve(double x1,double x2)    //在x1和x2中二分找答案
28 {
29     double L=x1,R=x2;
30     while(R-L>1e-4)    //这里的eps一般要比题中要求的精度(1e-2)多两位。
31     {
32         double mid=(L+R)/2;
33         double t1=f(L);
34         double t2=f(mid);
35         double t3=f(R);
36         if(t2==0) return mid;
37         if(t1*t2<0) R=mid;
38         else if(t2*t3<0) L=mid;
39     }
40     return (L+R)/2;//返回L,R,(L+R)/2都行
41 }
42
43 int main()
44 {
45     #ifdef DEBUG
46     freopen("sample.txt","r",stdin);
47     #endif
48
49     scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
50     double pre=f(-100.0);
51     for(int i=-100;i<=100;i++)
52     {
53         double t=f(i);
54         if(t!=0)
55         {
56             if(t*pre<0) ans.push_back(solve(i-1,i));
57         }
58         else ans.push_back(i);
59         pre=t;
60     }
61     for(int i=0;i<3;i++)
62         printf(i==2?"%.2f\n":"%.2f ",ans[i]);
63
64     return 0;
65 }

下面是我看别的大佬写的

盛金公式:

 1 #include <iostream>
 2 #include <math.h>
 3 #include <iomanip>
 4 using namespace std;
 5 int main()
 6 {
 7      double a,b,c,d;
 8      double as,bs,t,si;
 9      double x1,x2,x3;
10      cin>>a>>b>>c>>d;
11      as=b*b-3*a*c;
12      bs=b*c-9*a*d;
13      t=(2*as*b-3*a*bs)/(2*sqrt(as*as*as));
14      si=acos(t);
15      x1=(-b-2*sqrt(as)*cos(si/3))/(3*a);
16      x2=(-b+sqrt(as)*(cos(si/3)+sqrt(3)*sin(si/3)))/(3*a);
17      x3=(-b+sqrt(as)*(cos(si/3)-sqrt(3)*sin(si/3)))/(3*a);
18      cout<<fixed<<setprecision(2)<<x1<<" ";
19      cout<<fixed<<setprecision(2)<<x3<<" ";
20      cout<<fixed<<setprecision(2)<<x2<<" ";
21      return 0;
22 }

最后是EarthGiao大佬写的题解:

导数+勘根定理+牛顿迭代.

先对函数求导,f‘(x)=3ax^2+2*bx+c.

然后直接求根公式求f‘(x)=0的点,也就是函数极点.

这题保证有三个不定根,所以有两个单峰.

我们分别设这两个点为p,q.

然后显然的必有三个根在[-100,p),[p,q],(q,100]三个区间内 (两极点间必定存在零点,勘根定理).

然后用神奇的牛顿迭代法多次迭代就好了.

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #define eps 1e-4
 5 using namespace std;
 6 double x1,x2,x3,a,b,c,d;
 7 double f(double x){return a*x*x*x+b*x*x+c*x+d;}
 8 double df(double x){return 3*a*x*x+2*b*x+c;}
 9 double slove(double l,double r)
10 {
11     double x,x0=(l+r)/2;
12     while(abs(x0-x)>eps)
13       x=x0-f(x0)/df(x0),swap(x0,x);
14     return x;
15 }
16 int main()
17 {
18     cin>>a>>b>>c>>d;
19     double p=(-b-sqrt(b*b-3*a*c))/(3*a);
20     double q=(-b+sqrt(b*b-3*a*c))/(3*a);
21     x1=slove(-100,p),x2=slove(p,q),x3=slove(q,100);
22     printf("%.2lf %.2lf %.2lf",x1,x2,x3);
23     return 0;
24 }

-

原文地址:https://www.cnblogs.com/jiamian/p/12388066.html

时间: 2024-10-04 20:50:47

一元三次方程求解(数学、二分)的相关文章

洛谷 [P1024]一元三次方程求解【二分答案】

题目链接:https://www.luogu.org/problemnew/show/P1024 题目描述 有形如: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,

【noi 2.2_7891】一元三次方程求解(二分枚举)

对于noi上的题有2中解法: 1.数据很小(N=100),可以直接打for循环枚举和判断. 2.不会“三分”,便用二分.利用“两根相差>=1”和 f(x1)*f(x2)<0,转换意思为[x,x+1]内不会包含两个根,这样枚举可以保证不漏解.因此,枚举一个个根所在的区间,再用二分枚举找出根.其中,若N=10^5,由于保留2位小数,最好精确到4位小数计算.时间复杂度 O(N)=10^5+3*log(10^4),约为10^5. 以下附上二分的代码—— 1 //20160908 Ann 2 #incl

Vijos P1116 一元三次方程求解【多解,暴力,二分】

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

[NOIP提高&amp;洛谷P1024]一元三次方程求解 题解(二分答案)

[NOIP提高&洛谷P1024]一元三次方程求解 Description 有形如: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)之间一定

NOIP2001 一元三次方程求解

题一  一元三次方程求解(20分) 问题描述 有形如: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  

一元三次方程求解(折半查找)

Description 有形如:ax3+bx2+cx+d=0  这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,d  均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1.请你求出这个方程的三个实根. Input 只有一行,包括4个实数a,b,c,d,中间用一个或多个空格隔开. Output 只有一行,包括三个整数,为由小到大排列的三个实根(根与根之间留有空格),并精确到小数点后2位. Sample Input 1   -5   -4

算法训练——一元三次方程求解

//一元三次方程求解 //直接枚举 #include<stdio.h> #include<math.h> double a,b,c,d,x; double f(double x){ return a*x*x*x + b*x*x + c*x + d; } int main(){ scanf("%lf%lf%lf%lf",&a,&b,&c,&d); for(x=-100;x<=100;++x){ double z = x,y =

1238:一元三次方程求解

[原始题目] 1238:一元三次方程求解 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 4113 通过数: 2017 [题目描述] 形如:ax3+bx2+cx+d=0ax3+bx2+cx+d=0 这样的一个一元三次方程. 给出该方程中各项的系数(a,b,c,da,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在−100−100至100100之间),且根与根之差的绝对值≥11.要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后22位.

二分查找(vijos1116一元三次方程求解NOIP2001第一题)

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