题目传送门:1.UVa 原网站
题目大意:本题含有多组测试数据。n 个选手参加比赛,比赛分为跑步和骑车两项,跑步的距离为 r km,骑车的距离为 k km,且总长为 ( r + k ) = t。已知每位选手分别进行两种项目时的速度 V1 , V2。其中,有一名选手对裁判员进行了贿赂,希望获得冠军,求:是否可以通过调整各项目的距离使这一名选手获胜。如果可以获胜,还需输出与第二名的耗时之差的最大值及此时各项目的距离。如果不能,则输出 -1。( n ≤ 20 , t ≤ 100 )
题目分析:
由题,通过分析,我们发现这名“贿赂者”选手与其它选手中最优者耗时之差为单峰函数,于是可以进行三分操作。(你问我为什么是单峰函数?把距离设为横轴,耗时之差设为纵轴,然后对于不同的距离求出不同的耗时之差,画个图就出来了,就是这样)
三分操作的方法:设答案的下界为 left,上界为 right;然后对于 left ~ right 之间的两个三分点设为 lm 和 rm,其中 lm = left + ( right - left ) / 3,rm = right - ( right - left ) / 3。如果该函数为上凸函数,当 lm < rm 时,那么就在 [ lm , right ] 之内查找,否则在 [ left , rm ] 内查找;如果该函数为下凸函数,当 lm < rm 时,那么就在 [ left , rm ] 之间查找,否则在 [ lm , right ] 内查找。
如果还有疑问,请戳这里:http://blog.youkuaiyun.com/u012469987/article/details/50897291
下面附上代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MXer = 22;
const double esp = 1e-5;
const double INF = 1e13;
int t,n;
double run[MXer],cycle[MXer]; //跑步和骑车分别花的时间
double judge(double val){ //判断耗时之差
double mint = INF;
for (int i = 1;i < n;i++){
double tmp = (val / run[i]) + (t - val) / cycle[i];
if (tmp < mint) mint = tmp;
}
double cheater = (val / run[n]) + (t - val) / cycle[n];
return cheater - mint;
}
int main(){
while (scanf("%d",&t) != EOF){
double lf = 0.0,rt = t * 1.0; //表示 R 的值
memset(run,0,sizeof(run));
memset(cycle,0,sizeof(cycle));
cin>>n;
for (int i = 1;i <= n;i++){
cin>>run[i]>>cycle[i];
}
double lm = lf + ( rt - lf ) / 3,rm = rt - ( rt - lf ) / 3;
while (rt - lf > esp){
lm = lf + ( rt - lf ) / 3,rm = rt - ( rt - lf ) / 3;
if (judge(lm) < judge(rm)){
rt = rm;
} else {
lf = lm;
}
}
if (judge(lf) < 0){ //最好情况下比第二名快
printf("The cheater can win by %0.0lf seconds with r = %0.2lfkm and k = %0.2lfkm.\n",judge(lf) * (-3600),lf,t - lf);
//把超越的时间(负数)变成正的秒数
} else { //比第二名慢
printf("The cheater cannot win.\n");
}
}
return 0;
}