BZOJ 3379: [Usaco2004 Open]Turning in Homework 交作业
Description
贝茜有C(1≤C≤1000)门科目的作业要上交,之后她要去坐巴士和奶牛同学回家.
每门科目的老师所在的教室排列在一条长为H(1≤H≤1000)的走廊上,他们只在课后接收作业.交作业不需要时间.贝茜现在在位置0,她会告诉你每个教室所在的位置,以及走廊出口的位置.她每走1个单位的路程,就要用1秒.她希望你计算最快多久以后她能交完作业并到达出口.
Input
第1行输入三个整数C,H,B,B是出口的位置.之后C行每行输入两个整数,分别表示一个老师所在的教室和他的下课时间.
Output
贝茜最早能够到达出口的时间.
Sample Input
4 10 3
8 9
4 21
3 16
8 12
8 9
4 21
3 16
8 12
Sample Output
22
解法:一个经典的DP。令dp[i][j][0/1] 表示除了i~j这段区间没完成其他的都完成了,然后现在要完成i(0)或j(1)的最短时间。这样子就是从一个大区间F[1][n] 推到F[i][i] ,最后我们就能比较从哪个位置前往终点最优了。
转移方程跟第一种想法差不多,只不过第一种想法是用小区间推大区间,所以会导致答案不能保证最优。
#include <bits/stdc++.h> using namespace std; int C, H, B; int dp[1005][1005][2]; struct node{ int x, t; bool operator<(const node &rhs)const{ return x<rhs.x; } }A[1005]; int main() { scanf("%d %d %d", &C,&H,&B); for(int i=1; i<=C; i++){ scanf("%d %d", &A[i].x, &A[i].t); } sort(A+1,A+C+1); memset(dp, 0x7f, sizeof(dp)); dp[1][C][0] = max(A[1].x, A[1].t); dp[1][C][1] = max(A[C].x, A[C].t); for(int i=1; i<=C; i++){ for(int j=C; j>=1; j--){ dp[i][j][0] = min(dp[i][j][0], max(dp[i-1][j][0]+A[i].x-A[i-1].x, A[i].t)); dp[i][j][0] = min(dp[i][j][0], max(dp[i][j+1][1]+A[j+1].x-A[i].x, A[i].t)); dp[i][j][1] = min(dp[i][j][1], max(dp[i-1][j][0]+A[j].x-A[i-1].x, A[j].t)); dp[i][j][1] = min(dp[i][j][1], max(dp[i][j+1][1]+A[j+1].x-A[j].x, A[j].t)); } } int ans = INT_MAX; for(int i=1; i<=C; i++){ ans = min(ans, min(dp[i][i][0], dp[i][i][1])+abs(B-A[i].x)); } printf("%d\n", ans); return 0; }