http://acm.hdu.edu.cn/showproblem.php?pid=3714
题目大意:给你n个二次函数Si(x),作函数F(x) = max(Si(x)),求F(x)在[0,1000]上的最小值。
最大值最小值问题可以想到二分,但这个函数貌似不是单调的,而是先减后增的,因为给定的是n个二次函数,又给定了区间,所以要么单减要么单增要么增减要么减增的,所以最大值连起来是个单峰函数,所以可以用三分。
三分就是为对付非单调函数但是单峰函数的,不是将区间二等分而是三等分,每次取一个lm,一个rm,lm = l + (r - l) / 3; rm = r - (r - l) / 3; 然后搜索方式与二分类似,对于求极小值的情况,若lm比rm低(即lm对应的函数值 < rm函数值)则极小点肯定在[ l, rm ] ,反之在[ lm, r ]。
https://blog.csdn.net/u012469987/article/details/50897291
这是大神写的二分三分法的详解,可以参考。
那么这题的方法就很明了了,但有一点要注意,精度要到1e-9才够。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n;
double a[10010],b[10010],c[10010];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
}
double lm,rm,l=0,r=1000;
while(r-l>1e-9)
{
double max1=-5000000000,max2=-5000000000;
lm=l+(r-l)/3.0;
rm=r-(r-l)/3.0;
for(int i=1;i<=n;i++)
{
max1=max(a[i]*lm*lm+b[i]*lm+c[i],max1);
max2=max(a[i]*rm*rm+b[i]*rm+c[i],max2);
}
if(max1<max2)
{
r=rm;
}
else
{
l=lm;
}
}
double max1=-5000000000;
for(int i=1;i<=n;i++)
{
max1=max(a[i]*lm*lm+b[i]*lm+c[i],max1);
}
printf("%.4lf\n",max1);
}
return 0;
}