hihoCoder#1090

题目地址:

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;
}



你可能感兴趣的:(hihoCoder#1090)