P1024 一元三次方程求解 (二分&暴力&牛顿迭代)
题意:给定一元三次方程求解三个根。
思路:sol 1:枚举每个长度为1的区间,对每个区间进行二分。 sol 2:暴力从-100, 100 每次1e-3的枚举。
sol 3:求出函数的两个极值点 ,然后分成三个区间进行牛顿迭代。
二分AC代码:
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d;
double fun(double x){
return a*pow(x,3)+b*pow(x,2)+c*x+d;
}
int main(){
cin>>a>>b>>c>>d;
int cnt=0;
for(int i=-100;i<=100;i++){
double l=i,r=i+1;
double s=fun(l),t=fun(r);
if(!s){ //特判端点.
printf("%.2lf ",l);
cnt++;
}
if(s*t<0){//如果区间内有解
while(r-l>1e-4){ //二分
double mid=(l+r)/2.0;
if(fun(l)*fun(mid)<0)
r=mid;
else l=mid;
}
printf("%.2lf ",r);
cnt++;
}
if(cnt==3) break;
}
puts("");
return 0;
}
暴力AC代码:
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d;
double fun(double x){
return a*pow(x,3)+b*pow(x,2)+c*x+d;
}
int main(){
cin>>a>>b>>c>>d;
for(double i=-100;i<=100;i+=1e-3){
double j=i+1e-3;
if(fun(i)*fun(j)<=0)
printf("%.2lf ",(i+j)/2.0);
}
puts("");
return 0;
}
牛顿迭代:
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d;
double f(double x){
return a*pow(x,3)+b*pow(x,2)+c*x+d;
}
double f1(double x){//导数
return 3*a*x*x+2*b*x+c;
}
double fun(double l,double r){
double now=(l+r)/2.0,nt=0;
while(abs(now-nt)>1e-4){
nt=now-f(now)/f1(now);
swap(nt,now);//这里当前的迭代值成为下一次需要迭代的值。nt变成上一次的now
}
return nt;
}
int main(){
cin>>a>>b>>c>>d;
double q1=(-b-sqrt(b*b-3*a*c))/(3*a);//q1,q2表示两个极值点.
double q2=(-b+sqrt(b*b-3*a*c))/(3*a);
double ans1=fun(-100,q1),ans2=fun(q1,q2),ans3=fun(q2,100);
printf("%.2lf %.2lf %.2lf\n",ans1,ans2,ans3);
return 0;
}