题目描述
给定 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] 上的最小值。答案精确到小数点后四位,四舍五入。
说明/提示
对于 50% 的数据,n≤100。
对于 100% 的数据,T<10, n≤104,0≤a≤100,∣b∣≤5×103,∣c∣≤5×103。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int a[MAXN], b[MAXN], c[MAXN];
int n;
double F(double x) {
double res = -1e18;
for (int i = 0; i < n; i++) {
res = max(res, a[i]*x*x + b[i]*x + c[i]);
}
return res;
}
int main() {
int T;
cin >> T;
while (T--) {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i] >> b[i] >> c[i];
}
double l = 0.0, r = 1000.0;
while (r - l > 1e-9) { // 保证精度
double lmid = l + (r - l) / 3;
double rmid = r - (r - l) / 3;
if (F(lmid) < F(rmid))
r = rmid;
else
l = lmid;
}
printf("%.4f\n", F(l));
}
return 0;
}
F(x) 表示:在每个 x 位置上,取所有函数中值最大的那一个
由于 a≥0,每个函数是凹的。它们的最大值组成的函数F(x)还是凹的
F(x) 先下降、后上升
三分法的思路是:
-
找出两个三分点
lmid
,rmid
-
比较 F(lmid) 和 F(rmid)
-
因为 F(x) 是凹函数(先降后升),
-
如果
F(lmid) < F(rmid)
,说明最小值在左侧 -
否则在右侧
-
-
不断缩小区间
l
到r
直到区间极小(小于 10^-9),我们认为找到了极小值点。
由于浮点数存在精度问题,当进行多次计算时,会有非常微小的误差。如果使用 l <= r
,在接近正确解的时候,l
和 r
可能永远不完全相等,所以会陷入死循环。
-
精度终止条件:使用
r - l > epsilon
(比如1e-9
)可以确保在精度范围内停止,不依赖于l
和r
是否恰好相等。只要它们之间的差距小到几乎无法再缩小,就认为已经找到了最优解