1. 程式人生 > >BZOJ 3379: [Usaco2004 Open]Turning in Homework 交作業

BZOJ 3379: [Usaco2004 Open]Turning in Homework 交作業

() sam sca operator 計算 images its main src

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

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

BZOJ 3379: [Usaco2004 Open]Turning in Homework 交作業