ZCMU-1814: 一元三次方程求解(扩大后枚举)

 

1814: 一元三次方程求解

时间限制: 1 Sec  内存限制: 128 MB
提交: 22  解决: 15
[提交][状态][讨论版]

题目描述

有形如:ax3+bx2+cx+d=0  这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d  均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值> =1。要求三个实根。。

 

输入

 四个实数:a,b,c,d。数据规模和约定   |a|,|b|,|c|,|d|< =10

输出

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

样例输入

1 -5 -4 20

样例输出

-2.00 2.00 5.00

提示

 

来源

 

【解析】

哎呀,其实这个就是,那个什么,就是那个,对,很简单的莫。

看一题目说存在三个不同的根,嗯!范围还是-100--100,嗯!根与根之间的差>=1,(PS:其实一开始我不知道这个条件有什么用,WA了一次我知道干嘛用了。。。。)

一般这种数据规模这么小的,没有好的想法只能枚举了呗,但是这个枚举需要一点小tips,就是先扩大100倍(因为要精确到两位小数)然后再算,当然不用也可以,for里面的步长改为0.01应该也行。

#include <bits/stdc++.h>
using namespace std;
double a, b, c, d;
double f(double x)
{
	return a * x*x*x + b * 1.0 * x*x + c * 1.0 * x + d;//这个没什么好说的
}
int main()
{
	double temp1,temp2;
	while (~scanf("%lf%lf%lf%lf", &a, &b, &c, &d))
	{
		int flag = 1;					//用来控制输出格式
		for (double i = -10000; i <= 10000; i++)//扩大100倍
		{
			temp1 = (i - 0.5)/ 100.0;			//这里就是我一开始不懂为什么要说两根只差绝对值小于等于1的地方了
			temp2 = (i + 0.5)/ 100.0;			//因为……什么呢,四舍五入啊。。。。。。
			if (f(temp1)*f(temp2)<0)
			{
				if (flag)				//第一次输出不带空格,以后都带
				{
					printf("%.2lf", i / 100.0);
					flag = 0;
					continue;
				}
				else printf(" %.2lf", i / 100.0);
			}
		}
		puts("");							//格式控制一下,也没什么好说的,(那我为什么要说这么多)
											//我就是未来程序员特别的那个,特别喜欢写注释,YEAH~
	}
	return 0;
}

这个其实太麻瓜了。百度了一下一元三次方程其实是有通解方法的。

/*以下与A题目无关,赶时间的上面看完可以走了*/

这要用到高数的知识,一元三次方程的导数f'(x)=3ax^2+2bx+c。然后解个方程3ax^2+2bx+c=0,求得的两个根x1,x2就是极值点,那么f(x)=0的3个根就应该在区间[-100,x1]、[x1,x2]、[x2,100]中。无视开闭,关系不大。

然后再用二分法,很快就找到三个解了。

找来的代码,看看就好。

#include <stdio.h>
#include <math.h>
#define MIN_ERR 1e-4
double a, b, c, d;
double f(double x)
{
	return a * x*x*x + b * x*x + c * x + d;
}
double find_sol(double min, double max)
{
	if (max - min<MIN_ERR) return (min + max) / 2;
	else
	{
		double f1, f2, f3;
		f1 = f(min);
		f2 = f((min + max) / 2);
		f3 = f(max);
		if (f2 == 0) return (min + max) / 2;
		else if (f1*f2<0) return find_sol(min, (min + max) / 2);
		else return find_sol((min + max) / 2, max);
	}
}
int main()
{
	double x1, x2;
	scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
	if (a<0)
	{
		a = -a;
		b = -b;
		c = -c;
		d = -d;
	}
	x1 = (-2 * b - sqrt(4 * b*b - 12 * a*c)) / (a * 6);
	x2 = (-2 * b + sqrt(4 * b*b - 12 * a*c)) / (a * 6);
	printf("%.2lf %.2lf %.2lf\n", find_sol(-101, x1), find_sol(x1, x2), find_sol(x2, 101));
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值