原题
题目描述
给定 n 个二次函数 f1(x),f2(x),…,fn(x)(均形如 ax2+bx+c),设 𝐹(𝑥)=F(x)=max{f1(x),f2(x),...,fn(x)},求 𝐹(𝑥)F(x) 在区间[0,1000] 上的最小值。
输入格式
输入第一行为正整数 T,表示有 T 组数据。
每组数据第一行一个正整数 n,接着 n 行,每行 3 个整数a,b,c,用来表示每个二次函数的 3 个系数,注意二次函数有可能退化成一次。
输出格式
每组数据输出一行,表示 F(x) 的在区间[0,1000] 上的最小值。答案精确到小数点后四位,四舍五入。
输入输出样例
输入 #1
2 1 2 0 0 2 2 0 0 2 -4 2
输出 #1
0.0000 0.5000
说明/提示
解题思路
这是一个二分方法。
其实想到了这题就很简单,F(x)就是由[0,1000]区间内f1,f2等函数的最大值构成的,那么F(x)也一定是一个凹的,这样我们在[l,r]只要找到mid(f2),然后找到mid-eps(f1),mid+eps(f3),如果f1>f2,f3>f2,那么答案就出来了,f1<f2<f3代表是单调递增,缩小范围[l,mid-eps],反之就往[mid+eps,r]找,直到满足条件。
AC代码
#include <iostream>
#define eps 0.00000001//大于这个就精度出问题
using namespace std;
#include <algorithm>
int n,T;
double a[10009],b[10009],c[10009],f1,f2,f3;//a,b,c必须是double,不然强转会浪费很多时间
double function(double x){
double res=-1000000000;
for(int i=1;i<=n;i++) res=max(res,a[i]*x*x+b[i]*x+c[i]);
return res;
}
int main(){
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
double l=0,r=1000;
double mid=(l+r)/2,f1,f2,f3;
f1=function(mid-eps);
f2=function(mid);
f3=function(mid+eps);
while(!((r-l<eps)||((f1>f2)&&(f3>f2)))){//r-l>eps||!((f1>f2)&&(f3>f2))
if((f1>f2)&&(f2>f3)) l=mid+eps;
if((f1<f2)&&(f2<f3)) r=mid-eps;
mid=(l+r)/2;
f1=function(mid-eps);
f2=function(mid);
f3=function(mid+eps);
}
printf("%.4lf\n",f2);
}
return 0;
}