题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5935
题意:一辆车在路上直线走,它的速度是不减的,现在有一些该车路过的坐标,测的时刻是整数时刻,最后一个测值位置点是终点(这一点题目没说,我觉得不严谨)。问车开到终点的最少用时?
解题思路:我们知道,由于时间是整数,车的速度是相等或递增的,那么我们尽量让车速最快。我们从最后一段路程入手,令车通过该段路程的时间为1,这样做的目的是使得车速最大,(因为时间是整数值,最小就是1了),使最后一段路程的速度最大的目的是为了最大化前面的所有路程的速度(因为车速是不递减的)。那么我们得到了最后一段路程的最大速度(其实就是长度len),往前递推前面的路程的速度和用时:
1)后一段路的最大速度v大于前一段路的路程长度len,那么我们继续用这个最大速度v走这前面的一段路,耗时最少,为1秒,同时也保持了最大速度。
2)后一段路的最大速度v小于前一段路的路程长度len
2.1) 若len是v的整数倍,则这段路耗时len / v
2.2)若len不是v的整数倍,则这段路程耗时len / v + 1
(对于double型如何判断倍数关系?其实只需要在做除法前-eps就可以实现了,因为对于double型我们认为[x-eps,x+eps]都是等于x的,那么如果对x减去一个eps则新的x属于[x-2eps,x],此时对结果取整就能实现不是整数倍时不加一的这个目的了)
AC代码:
#include<cstdio>
const int maxn = 100005;
int pos[maxn];
const double eps = 1e-8;
int main()
{
int t,n;
scanf("%d", &t);
for (int m = 1; m <= t; m++)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &pos[i]);
double v = 1.0 * (pos[n]-pos[n-1]);
int ans = 1;
for (int i = n-1; i >= 1; i--)
{
double len = 1.0 * (pos[i] - pos[i-1]);
if (v >= len-eps)
{
v = len;
ans++;
}
else
{
double t = int((len-eps)/v) + 1;//-eps使得v整除len的时候值比不整除时少一
v = len / t;
ans += t;
}
}
printf("Case #%d: %d\n",m,ans);
}
return 0;
}