题目链接
一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1435。
自己OJ:http://47.110.135.197/problem.php?id=4460。
题目
题目描述
明明做作业的时候遇到了 n 个二次函数 ,他突发奇想设计了一个新的函数
。
明明现在想求这个函数在 [0,1000] 的最小值,要求精确到小数点后四位四舍五入。
输入
输入包含T 组数据 (T < 10) ,每组第一行一个整数 n(n ≤ 10000) ,之后n行,每行3个整数a (0 ≤ a ≤ 100), b (|b| ≤ 5000), c (|c| ≤ 5000) ,用来表示每个二次函数的3个系数,注意二次函数有可能退化成一次。
输出
每组数据一个输出,表示新函数 F(x) 的在区间 [0,1000] 上的最小值。精确到小数点后四位,四舍五入。
样例输入
2
1
2 0 0
2
2 0 0
2 -4 2
样例输出
0.0000
0.5000
数据范围
T < 10,n ≤ 10000,0 ≤ a ≤ 100,|b| ≤ 5000, |c| ≤ 5000
分析
题意分析
提供了 n 个二次函数 ,将这 n 函数构造成一个组合函数
,然后求 max(G(x)) 在 [0, 1000] 这个区间的最小值。下面来分析样例数据,样例输入如上。
第一组输入,我们知道 n=1,对应的 ,那么
,求
在区间 [0, 1000] 的最小值,自然我们知道最小值是当 x=0 的时候,对应的最小值为 0.0000。
第二组输入,我们知道 n=2,对应的 ,那么对应的
,求 max(G(x)) 在区间 [0, 1000] 的最小值。最小值出现在当 x = 0.5 的时候,
,对应的最小值为 0.5000。
算法思路
一题典型的浮点数二分查找。
二分查找
1、在 left=0,right=1000 这个范围进行三分查找。
2、只要左边界和右边界之间差值大于某个精度,即 fabs(right - left) > eps ,进行三分查找。
3、计算右中间值(r_mid),使用右中间值计算出 max(G(x)),记为 ans_r。
4、计算左中间值(l_mid),使用左中间值计算出 max(G(x)),记为 ans_l。
5、比较 ans_r 和 ans_l 关系。当 时,移动右边界 right=r_mid;否则移动左边界 left=l_mid。
AC参考代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4;
int a[MAXN];//系数a数组
int b[MAXN];//系数b数组
int c[MAXN];//系数c数组
//计算max(s(x))
double calc(double x, int n) {
double ans = -1e9;
for (int i=0; i<n; i++) {
ans = max(ans, a[i]*x*x+b[i]*x+c[i]);
}
return ans;
}
int main() {
int t;
cin >> t;
int i, j;
for (i=0; i<t; i++) {
int n;
cin >> n;
for (j=0; j<n; j++) {
cin >> a[j] >> b[j] >> c[j];
}
//使用三分
double left = 0;
double right = 1000;
double l_mid;
double ans1;
double r_mid;
double ans2;
double eps = 1e-9;//精度
while (fabs(right-left)>eps) {
l_mid = left+(right-left)/3;
r_mid = right-(right-left)/3;
ans1 = calc(l_mid,n);
ans2 = calc(r_mid,n);
if (ans1<=ans2) {
right = r_mid;
} else {
left = l_mid;
}
}
printf("%.4lf\n", ans1);
}
return 0;
}