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

1000ms       128MB

题目描述

有形如: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)之间一定有一个根。

输入输出格式

输入格式:

一行,4个实数A,B,C,D。

输出格式:

一行,三个实根,并精确到小数点后2位。

输入输出样例

输入样例
1 -5 -4 20
输出样例
-2.00 2.00 5.00

做这个题的时候我想的是二分,然后呢,由于学艺不精,二分没过,然后就想了一下暴力,果然暴力出奇迹,看了题解发现有用牛顿迭代法的,最后还有一个是用盛金公式做的,所以这个题就可以用四种方法做了。



暴力
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <cstring>
#include <string>
#include <queue>
#include <deque>
#include <stack>
#include <stdlib.h>
#include <list>
#include <map>
#include <utility>
#include <set>
#include <bitset>
#include <vector>
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fLL
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int min3(int a,int b,int c){return min(min(a,b),c);}
int max3(int a,int b,int c){return max(max(a,b),c);}
int gcd(int x, int y){if(y==0)return x;return gcd(y, x%y);}
int main()
{
   double a,b,c,d;
   scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
   for(double i=-100;i<=100;i+=0.001)
   {
      double j=i+0.001;
      double y1=a*i*i*i+b*i*i+c*i+d;
      double y2=a*j*j*j+b*j*j+c*j+d;
      if(y1*y2<0)
      {
         double x=i;
         printf("%.2lf ",x);
      }
   }
}
二分
因为区间很大,所以可以二分。
三个答案都在[
-100,100]范围内,两个根的差的绝对值>=1,保证了每一个大小为1的区间里至多有1个解,也就是说当区间的两个端点的函数值异号时区间内一定有一个解,同号时一定没有解。那么我们可以枚举互相不重叠的每一个长度为1的区间,在区间内进行二分查找。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <cstring>
#include <string>
#include <queue>
#include <deque>
#include <stack>
#include <stdlib.h>
#include <list>
#include <map>
#include <utility>
#include <set>
#include <bitset>
#include <vector>
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fLL
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int min3(int a,int b,int c){return min(min(a,b),c);}
int max3(int a,int b,int c){return max(max(a,b),c);}
int gcd(int x, int y){if(y==0)return x;return gcd(y, x%y);}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;}
double a,b,c,d;
double fc(double x)
{
    return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
    double l,r,m,y1,y2;
    int cnt=0;
    scanf("%lf%lf%lf%lf",&a,&b,&c,&d);

    for(int i=-100;i<=100;i++)
    {
        l=i;
        r=i+1;
        y1=fc(l);
        y2=fc(r);
        if(!y1)
        {
            printf("%.2lf ",l);
            cnt++;
        }//判断左端点,是零点直接输出。
        //不能判断右端点,会重复。

        if(y1*y2<0)
        {
            while(r-l>=0.001)
            {
                m=(l+r)/2;
                if(fc(m)*fc(r)<0)
                    l=m;
                else
                    r=m;
            }
            printf("%.2lf ",r);
            cnt++;
        }
        if(cnt==3)
            break;//找到三个就退出大概会省一点时间
    }
    printf("\n");

    return 0;
}
牛顿迭代法

对于一个已知的x值,每一次根据函数在这一点的导数,把x移动到,切线与x轴相交的地方。

即x[n+1]=x[n]-f(x)/f'(x),可以证明结果会趋近于函数的一个解,据说这种方法比二分要快。


不会,未完,待续



盛金公式  
一元三次方程:aX的三次方+bX的二次方+cX+d=0
重根判别公式:
     A=b的二次方-3ac
     B=bc-9ad
     C=c的二次方-3bd
当A=B=0时,X1=X2=X3= -b/3a= -c/b = -3d/c


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <cstring>
#include <string>
#include <queue>
#include <deque>
#include <stack>
#include <stdlib.h>
#include <list>
#include <map>
#include <utility>
#include <set>
#include <bitset>
#include <vector>
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fLL
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int min3(int a,int b,int c)
{
    return min(min(a,b),c);
}
int max3(int a,int b,int c)
{
    return max(max(a,b),c);
}
int gcd(int x, int y)
{
    if(y==0)return x;
    return gcd(y, x%y);
}
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}

int main()
{
    double a,b,c,d;  //定义四个系数
    double x;
    double x1,x2,x3; //定义三个实根
    cin>>a>>b>>c>>d;
    double A=b*b-3*a*c;  //第一重根判别式
    double B=b*c-9*a*d;  //第二重根判别式
    double C=c*c-3*b*d;  //第三重根判别式
    double del=B*B-4*A*C;  //总判别式
    if(A==B&&A==0)    //如果A=0且B=0
    {
        x1=x2=x3=(-1*b/(3*a));  //x1,x2,x3的值相同......
    }
    else if(del==0)   //如果△=0,x2与x3相同......
    {
        x1=(-1*b/a)+B/A;
        x2=x3=-1*B/A/2;
    }
    else if(del<0)  //如果△<0,有三实根......
    {
        double T=(2*A*b-3*B*a)/(2*A*sqrt(A));
        double _xt=acos(T);
        double xt=_xt/3;
        x1=(-1*b-2*sqrt(A)*cos(xt))/(3*a);
        x2=(-1*b+sqrt(A)*(cos(xt)+sqrt(3)*sin(xt)))/(3*a);
        x3=(-1*b+sqrt(A)*(cos(xt)-sqrt(3)*sin(xt)))/(3*a);
    }//由于题目说了只会出现实根,因此只有以上三种情况
    if(x1>x2)
    {
        x=x1;
        x1=x2;
        x2=x;
    }
    if(x1>x3)
    {
        x=x3;
        x3=x1;
        x1=x;
    }
    if(x2>x3)
    {
        x=x3;
        x3=x2;
        x2=x;
    }//题目要求从小到大输出三实根,进行排序。
    printf("%.2lf %.2lf %.2lf",x1,x2,x3);
    return 0;
}

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页