题目地址:
http://hihocoder.com/problemset/problem/1090
题目大意:
在一条单行路(只允许向着同一方向走)上有n辆车,第i辆车以不超过L[i]的速度从位置X[i]走到位置Y[i](X[i] < Y[i])。假设每辆车都是同时从起点出发,在行进过程中不允许有超车的现象,每辆车看做一个点,且速度变化过程是瞬间完成的。求每辆车在路上的行驶时间。
分析:
方便起见我们假设数据已经按照X[i]从小到大的顺序排好序(编号从0到n-1,如无特殊说明我们直接以i表示第i辆车),且每辆车总是在满足限制条件下以最快的速度行驶(这条贪心策略显然成立)。
仔细思考,可以发现下面两条性质:
性质一,即0,..,i-1对i,...,n-1没有影响。
性质二,最高速度大的车对最高速度小的车的影响可以忽略。
故计算i的行驶时间时,我们只考虑i+1,...,n-1中最高速度小于L[i]的车,我们称这些车为满足条件的车。
我们设solve(cur, term)表示编号为cur的车从X[cur]行驶到term所用的时间。
现在假设i+1,...,n-1完成各自路程的总时间ans[i+1],...,ans[n-1]我们已经得到,现在计算i的答案,等价于求solve(i, Y[i])。
solve(cur, term)
{
当可以直接得到答案时直接返回答案。
初始时,将s(当前阶段起点)设为X[cur],term(终点)设为Y[cur],tt(cur从X[cur]行驶到s所化时间)设为0。
设j为cur+1,...,n-1中从小到大第一辆车满足条件的车。
begin
情况一,Y[j] <= term。这时候要行驶到term,首先要到达Y[j],所以先考虑到达Y[j]的行驶时间。这时候会有两种情形,一种是cur不受j的阻碍的行驶到了Y[j],另一种是 cur收到j的阻碍行驶到Y[j]。第一种情形行驶到Y[j]的行驶时间为tt + (Y[j] - s) / L[cur],第二种情形行驶到Y[j]的行驶时间为j行驶到Y[j]的时间(也即ans[j])。我们只需令tt = max(tt + (Y[j] - s) / L[cur], ans[j]),将s设为Y[j]即可。然后我们令j为j + 1, ..., n - 1从小到大第一辆满足条件的车,然后回到begin处重新考虑j。
情况二,Y[j] > term。这是需要考虑cur和j行驶到term的时间。也是有两种情形,一种是cur不受j的阻碍的行驶到了term,另一种是cur收到j的阻碍行驶到term。第一种 情形行驶到term的行驶时间为tt + (term - s) / L[cur],第二种情形行驶到term的行驶时间为j行驶到term的时间(设该时间为T,我们无法直接得到T。但我们发现这实际上 就相当于计算j从X[j]行驶到term所用时间,我们可以递归的调用solve(j, term)得到T)。我们令tt = max(tt + (Y[j] - s) / L[cur], T),这时候tt即为cur从X[cur]行驶到term所用 时间,返回tt即可。
end
}
虽然是一个递归的过程,但注意到在所有递归过程中i+1,...,n-1中每辆车仅考虑了一次,因此求解solve(i, Y[i])为O(n)。
我们只需按照n-1,...,0的顺序调用solve即可得到所有答案,因此总的时间复杂度为O(n^2)。
叙述了很多,代码还是很短的。
#include<cstdio> #include<algorithm> using namespace std; struct REC{ double X, Y, L; int id; friend bool operator <(const REC &a, const REC &b){ return a.X < b.X; } } rec[1010]; double ans[1010]; int N; double solve(int cur, double term){ if (cur >= N || term <= rec[cur].X) return 0; //可以直接得到答案 double s = rec[cur].X, tt = 0; int j; for (j = cur + 1; j < N; ++j) if (rec[j].L < rec[cur].L){ //是否满足条件 if (rec[j].Y < term){//情况一 tt = max(ans[rec[j].id], tt + (rec[j].Y - s) / rec[cur].L); s = rec[j].Y; } else break; //情况二,可以和j==N时这种情况统一处理,因此放到了for的外面处理。 } double T = solve(j, term); tt = max(tt + (term - s) / rec[cur].L , T); return tt; } int main(){ scanf("%d", &N); for (int i = 0; i < N; ++i){ scanf("%lf%lf%lf", &rec[i].X, &rec[i].Y, &rec[i].L); rec[i].id = i; } sort(rec, rec + N); for (int i = N - 1; i >= 0; --i) ans[rec[i].id] = solve(i, rec[i].Y); for (int i = 0; i < N; ++i) printf("%.2f\n", ans[i]); return 0; }