[3014]曲线

曲线

Description

小Y同学的弟弟小Z昨天学习了数学中的一元二次函数,但是由于学业不精,他一个晚上都在缠着小Y问一元二次函数的极值问题,小Y烦不可耐,于是,想请你帮忙弄个程序来应付小Z。程序要完成以下任务:
给你N个二次函数,记第i个为:fi(x)=ai*x^2+bi*x+ci。(0≤ai≤100,|bi|≤5000,|ci|≤5000)
设函数F(x)=max{f1(x), f2(x) … fn(x)}。
请你求出F(x)的在区间[0, 1000]上的最小值,结果保留3位小数。

Input

第一行是一个整数N。
接下来N行,每行3个实数ai、bi、ci,之间有一个空格分隔。

Output

输出一行一个实数,表示F(x)的在区间[0, 1000]上的最小值。

Sample Input

#1
1
2 -4 2

#2
2
3 -2 1
2 -4 2

Sample Output

#1
0.000

#2
0.686

Hint

70%的数据:1≤N≤1000;
100%的数据:1≤N≤100000。

今天早上考了这题,交错了文件夹,惨惨。

由于算法不精,很多算法要么不知道,要么不会用,所以当时的思路很混乱,想分情况讨论但是WA的很精彩。

所以下午就认真听课了QwQ 废话不多说,我们分析一下这道题


随便画几个抛物线,我们会发现,我们要求的最大值,总是呈现凸壳型(这话对不对有待考证……),也就是,有一个最低点,其余都向左或向右递增(并非抛物线)

这种问题可以用二分来求,但是比较麻烦,由此引入三分(这是一个链接)这一神奇的算法

这题是三分模板题,三分横坐标逼近答案(注意最后要输出的是横坐标对应的纵坐标)

这题还有一个棘手的问题,就是精度,在程序里要控制好。

下面贴代码

#include "stdio.h"
#include "iostream"
#include "algorithm"
using namespace std;
int n;
struct node
{
	double a,b,c;
}x[100005];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lf%lf%lf",&x[i].a,&x[i].b,&x[i].c);
	double l=0.0,r=1000.0;       //左边界和右边界
	double xl,xr,yl,yr;
	while(r-l>1e-10)           //控制精度
	{
		xl=(r-l)/3.0+l,xr=2.0*(r-l)/3.0+l;              //三分的中间值
		yl=yr=-1e100;                   //先赋最小值
		for(int i=1;i<=n;i++)          //计算此下标所对应函数值的最大值
		{
			yl=max(yl,x[i].a*xl*xl+x[i].b*xl+x[i].c);
			yr=max(yr,x[i].a*xr*xr+x[i].b*xr+x[i].c);
		}
		if(yl>yr)
			l=xl;           //调整左边界
		else r=xr;           //调整右边界
	}
	printf("%.3lf\n",yl);
	return 0;
}

QVER~

因为是模板题,也没什么多说的,这种算法很巧妙,看完也就会了。

祝我和学长99(✺ω✺)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值