一元三次方程
题目描述
有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。
给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。
输入样例
1.0 -5.0 -4.0 20.0
输出样例
-2.00 2.00 5.00
##题目分析##
乍一看是一道数学题,没错确实可以用这种方法来做,但是当你遇到类似的题目,而又不知道公式的时候,就必须找另一种方法来解决,那我们就通过三种方法来讲述一下这道题目。
1:数学方法
2:模拟方法
3:分治方法
##数学方法##
这种方法就是直接套公式喽
如上图就是一元三次方程的公式
只需了解,背诵啥的等到高中吧(百度搜索:盛金公式)
#include <iOStream>
#include <math.h>
#include <iomanip>
using namespace std;
int main()
{
double a,b,c,d;
double as,bs,t,si;
double x1,x2,x3;
cin>>a>>b>>c>>d;
as=b*b-3*a*c;
bs=b*c-9*a*d;
t=(2*as*b-3*a*bs)/(2*sqrt(as*as*as));
si=acos(t);
x1=(-b-2*sqrt(as)*cos(si/3))/(3*a);
x2=(-b+sqrt(as)*(cos(si/3)+sqrt(3)*sin(si/3)))/(3*a);
x3=(-b+sqrt(as)*(cos(si/3)-sqrt(3)*sin(si/3)))/(3*a);
cout<<fixed<<setprecision(2)<<x1<<" ";
cout<<fixed<<setprecision(2)<<x3<<" ";
cout<<fixed<<setprecision(2)<<x2<<" ";
return 0;
}
代码就差不多长这样,没啥好说的
##模拟方法##
直接暴力枚举也是一种方法,只可惜可能没发过所有的数据
枚举的思路就是在-100到100的范围内,以0.01为基准(在洛谷提交的经验)一个一个从小到大搜,搜到了就输出,这种思路还是十分水的,然而令我不能接受的是,这种漏洞百出的思路似乎还可以ac,谁叫洛谷数据只用搜索200*100=20000次呢,这种大家可以用五分钟来写一下,真的很简单啊。
下面是代码
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d;
int main()
{
cin>>a>>b>>c>>d;
for(double i=-100.00;i<=100.00;i+=0.01)
{
if(a*i*i*i+b*i*i+c*i+d<0.00000001&&a*i*i*i+b*i*i+c*i+d>-0.00000001)
printf("%.2f ",i);
}
return 0;
}
看上去很简单(实际上也很简单),可是还有一处细节,因为我们c++的double是定义到12位数的,所以在执行aiii+bii+ci+d时,它也会自动算到很后面很后面的位置,达不到完全相等,所以我不写0,反而是写>0.00000000001类似的,这样的话就避免了程序本身误差出现的问题,大家可以试一下,写0的d得0分,写>0.00000001满分,这简直跟大头的尺寸一样令人惊讶。
##分治算法##
好了终于到正常的方法了,这是一道敲经典的分治问题。
那问题来了,分治怎么分,以什么作为端点来分治?首先采用的便是二分策略,左端点x到中间点mid,中间点mid再到右端点y,以此类推。
但是这样的分治方法似乎效率没法提高,题目中有一句话:记方程f(x)=0,若存在两个数x1,x2且x1x2,f(x)*f(x2)<0,则在x,x2这个范围之中一定有一个解,我们可能不能了解这句话什么意思,但是我们可以照着这句话来写。先贴一下代码,然后我们慢慢探讨。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
using namespace std;
double a,b,c,d;
int now=0;
double f(double x)
{
double res=a*x*x*x+b*x*x+c*x+d;
return res;
}
void ser(double x,double y)
{
if(y-x<0.005)
{
cout<<setprecision(2)<<x<<" ";
now++;
return ;
}
double mid = (x + y) / 2;
if(f(mid)==0)
{
cout<<setprecision(2)<<mid<<" ";
now++;
return ;
}
if(f(x)*f(mid)<0)
{
ser(x,mid);
}
if(f(mid)*f(y)<0)
{
ser(mid,y);
}
}
void work_()
{
for(double i=-100;i<100;i++)
{
if(f(i)==0)
{
printf("%0.2lf",i);
now++;
}
if(f(i)*f(i+1)<0)
{
ser(i,i+1);
}
if(now==3)
{
break;
}
}
}
int main()
{
cin>>a>>b>>c>>d;
work_();
return 0;
}
好,这里大致的思路已经ojbk了,那有几个细节,第一个地方就是变量now,now指的是当前有多少个解,一元三次方程只能有3个解,所以我们的now==3时,就停止运算,消减了很多的运算步骤。
还有就是当f(x)==0时,我们也是选择直接输出,多判断了一步,却可能省下很多步,十分的划算。
那好了,一元三次方程就讲完了
然后这道题方法很多,我再举出几种
比如数学超前学习的可以使用倒数来做,还有就是盛金公式的变化牛顿迭代法,有兴趣可以参考
相关阅读
一元抢拍是对一些中小卖家进行扶持活动,是不分太多等级制度的,可以根据自己店铺需要,进行报销参加,加大产品展现量。接下来小编为大家
拼多多商城推出了很多优惠活动,而且都是极其便宜的,比如9.9特卖,0.1元购还有秒杀活动,这些都是优惠促销活动,拼多多经常用这些活动来吸
很多人都会使用飞猪这个订票软件,因为确实还是有一定的知名度,也让人放心购买,但是在这个上面真的能够购买到一折机票吗?如果能够购
2016,后泡沫互联网时代,资本更加谨慎。因此最火的两个项目,就成了变现模式清晰的“直播”和“一元夺宝”分析直播的文章已经汗牛充栋
说起微信夺宝的内容,我想大家肯定会存在一些疑惑。那么今天小编要给大家讲述的内容是微信夺宝在哪打开?微信公众号一元怎么夺宝?希