vijos p1116(codevs 1038 )一元三次方程求解 題解

題目描述 Description

有形如:ax3+bx2+cx+d=0  這樣的一個一元三次方程。給出該方程中各項的係數(abcd  均爲實數),並約定該方程存在三個不同實根(根的範圍在-100100之間),且根與根之差的絕對值>=1。要求由小到大依次在同一行輸出這三個實根(根與根之間留有空格),並精確到小數點後2位。
提示:記方程
f(x)=0,若存在2個數x1x2,且x1<x2f(x1)*f(x2)<0,則在(x1x2)之間一定有一個 根。

輸入描述 Input Description

一個三次方程的各項係數

輸出描述 Output Description

三個解

樣例輸入 Sample Input

1   -5   -4   20

樣例輸出 Sample Output

-2.00   2.00   5.00

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

這道題是一道明顯的二分題。

有題可知精度爲0.01,且三個解均在-100到100之間。由於範圍小,精度確定,所以我們可以用二分的方法去求解。

網上有一些題解,這裏我給出我的,和大家一起共享。

首先我們可以求導,必然的到兩個極值點,而這兩個極值點是由a,b,c,決定的,及求導後得到的一元二次方程的解。這兩個極值便是我們劃分區間的界限(f(x1),f(x2))我們便可以得到一個區間——(-100,f(x1))(f(x1),f(x2))(f(x2),100)

由函數圖象的性質可知若一個區間的兩端的函數值乘積小於0,則這個區間上必有解,這樣我們就可以一直二分下去,知道區間的兩端之差<=0.01時便可以退出了。

關於二分,有興趣的讀者,可以看一下我的下一篇文章——《二分哪些事兒》

……比較坑的是,我把a*x*x*x+b*x*x+c*x+d寫成了a*x*x*x+b*x*x+c+d導致我一直輸出錯誤,大家一定要注意!

++++++++++++++++++++++++代碼如下+++++++++++++++++++++++++++++

首先是用二分的:

#include <cstdio>
#include <cmath>
using namespace std;
double a,b,c,d;

double fang(double x)
{
	 return a*x*x*x+b*x*x+c*x+d; 
}

double Bi_Search(double left,double right)//返回等於b的第一個
{
	double last = -1,mid ;
	while (left<=right)
	{	
		double mid = left +(right-left)/2;
		if(right-left<=0.01)
		{
			last = mid;
			right = mid -1;
		}
		else 
			if(fang(mid)*fang(right)<0)
			 left = mid;
             else
			 right = mid;
	}
	return last;

}

int main()
{
    cin>>a>>b>>c>>d;
    double aa=3*a,bb=2*b,x=100.00,y,m,n=-100.00;
    y=(-bb+sqrt(bb*bb-4*aa*c))/(2*aa);
    m=(-bb-sqrt(bb*bb-4*aa*c))/(2*aa); cout<<y<<" "<<m<<endl;
    double x1=Bi_Search(n,m),x2=Bi_Search(m,y),x3=Bi_Search(y,x);
    printf("%.2lf %.2lf %.2lf",x1,x2,x3);
    return 0;
}


這裏還有一個用公式直接求解的:

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
void mmax(double &x,double &y,double &z)
{
	double a[3];
	a[0]=x,a[1]=y,a[2]=z;
	sort(a,a+3);
	x=a[0],y=a[1],z=a[2];
	return ;
}

int main()
{
	double A,B,C,a,b,c,d;
	cin>>a>>b>>c>>d;
	A=b*b-3*a*c;
	B=b*c-9*a*d;
	C=c*c-3*b*d;
	double t=2*A*b-3*a*B;
	t/=2*sqrt(A*A*A);
	double cr=acos(t);
	double x_1,x_2,x_3;
	x_1=(-b-2*sqrt(A)*cos(cr/3))/3*a;
	x_2=(-b+sqrt(A)*(cos(cr/3)+sqrt(3)*sin(cr/3)))/3*a;
	x_3=(-b+sqrt(A)*(cos(cr/3)-sqrt(3)*sin(cr/3)))/3*a;
	mmax(x_1,x_2,x_3);
	printf("%0.2lf %0.2lf %0.2lf",x_1,x_2,x_3);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章