http://acm.hdu.edu.cn/showproblem.php?pid=3714
题目大意:给你
n
n
个二次函数,作函数
F(x)=max(Si(x))
F
(
x
)
=
m
a
x
(
S
i
(
x
)
)
,求
F(x)
F
(
x
)
在
[0,1000]
[
0
,
1000
]
上的最小值。
最大值最小问题可以想到二分,但这个函数貌似不是单调的,而是先减后增的,因为给定的是n个二次函数,又给定了区间,所以要么单减要么单增要么增减要么减增的,所以最大值连起来是个单峰函数,所以可以用三分。
三分就是为对付非单调函数但是单峰函数的,不是将区间二等分而是三等分,每次取一个
lm
l
m
,一个
rm
r
m
,
lm=l+(r−l)/3
l
m
=
l
+
(
r
−
l
)
/
3
;
rm=r−(r−l)/3
r
m
=
r
−
(
r
−
l
)
/
3
; 然后搜索方式与二分类似,对于求极小值的情况,若
lm
l
m
比
rm
r
m
低(即
lm
l
m
对应的函数值小于
rm
r
m
函数值)则极小点肯定在
[l,rm]
[
l
,
r
m
]
,反之在
[lm,r]
[
l
m
,
r
]
。
https://blog.csdn.net/u012469987/article/details/50897291
这是大神写的二分三分法的详解,可以参考。
那么这题的方法就很明了了,但有一点要注意,精度要到 10−9 10 − 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;
}