[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位小数。
给你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,之间有一个空格分隔。
接下来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
1
2 -4 2
#2
2
3 -2 1
2 -4 2
Sample Output
#1
0.000
#2
0.686
0.000
#2
0.686
Hint
70%的数据:1≤N≤1000;
100%的数据:1≤N≤100000。
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(✺ω✺)