[动态规划] UVa1025 城市里的间谍 (DAG的固定起点终点最长短路)

题目

这里写图片描述

思路

本题的难点在于抽象,由于时间本身就是一个天然的“序”,所以可以由时间和所在车站组成状态。
1.状态定义:(T,i),在T时刻位于i车站。
2.指针函数:d(T,i),还需在车站等待多长时间。
3.状态转移方程:
取决于对于每个状态,有三种决策:
- 等1分钟。
- 乘坐往右开的车,去向右第一个车站。(有车的话)
- 乘坐往做开的车,去向左第一个车站。(有车的话)

所以状态转移方程为:

d ( T , i ) = m i n ( d ( T + 1 , i ) + 1 , d ( T + t i m e [ i ] , i + 1 ) , d ( T + t i m e [ i 1 ] , i 1 ) )

代码

1.记忆化搜索:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define _for(i,a,b) for(int i =(a); i<(b); i++)
#define _rep(i,a,b) for(int i =(a); i<=(b); i++)
using namespace std;

const int INF = 1<<30;
const int maxn = 1000+100;
int time[maxn], has_train[maxn][maxn][2], d[maxn][maxn];
int TT, n, M1, M2;

int dp(int T, int i){
    int &ans = d[T][i];
    if (ans != -1) return ans;
    int d1 = dp(T+1,i)+1;
    int d2 = INF;
    if (i < n && has_train[T][i][0] && T+time[i] <= TT)
        d2 = dp(T+time[i],i+1);
    int d3 = INF;
    if (i > 1 && has_train[T][i][1] && T+time[i-1] <= TT)
        d3 = dp(T+time[i-1],i-1);
    ans = min(min(d1,d2), min(d1,d3));
    return ans;
}

int main(){
    int kase = 0;
    while(scanf("%d",&n) == 1 && n){
        scanf("%d",&TT);
        _rep(i,1,n-1) scanf("%d",&time[i]);
        int x;
        memset(has_train, 0, sizeof(has_train));
        scanf("%d",&M1);
        _for(i,0,M1){
            scanf("%d",&x);
            _rep(i,1,n-1) {
                has_train[x][i][0] = 1;
                x+=time[i];
            }
        }
        scanf("%d",&M2);
        _for(i,0,M2){
            scanf("%d",&x);
            for(int i = n; i>1; i--){
                has_train[x][i][1] = 1;
                x+=time[i-1];
            }
        }  // 输入完成 

        memset(d,-1,sizeof(d));
        _rep(i,1,n-1) d[TT][i] = INF; //小技巧:初始化一些无法达到终点的状态
        d[TT][n] = 0; //递归边界
        int ans = dp(0,1);
        printf("Case Number %d: ",++kase);
        if (ans >= INF) printf("impossible\n");
        else printf("%d\n",ans);
    }

    return 0;
} 

2.递推

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define _for(i,a,b) for(int i =(a); i<(b); i++)
#define _rep(i,a,b) for(int i =(a); i<=(b); i++)
using namespace std;

const int INF = 1 << 30;
const int maxn = 1000 + 100;
int time[maxn], has_train[maxn][maxn][2], d[maxn][maxn];
int TT, n, M1, M2;

int main() {
    int kase = 0;
    while (scanf("%d", &n) == 1 && n) {
        scanf("%d", &TT);
        _rep(i, 1, n - 1) scanf("%d", &time[i]);
        int x;
        memset(has_train, 0, sizeof(has_train));
        scanf("%d", &M1);
        _for(i, 0, M1) {
            scanf("%d", &x);
            _rep(i, 1, n - 1) {
                has_train[x][i][0] = 1;
                x += time[i];
            }
        }
        scanf("%d", &M2);
        _for(i, 0, M2) {
            scanf("%d", &x);
            for (int i = n; i>1; i--) {
                has_train[x][i][1] = 1;
                x += time[i - 1];
            }
        }  // 输入完成 

        _rep(i, 1, n - 1) d[TT][i] = INF;  // 表示无法到达
        d[TT][n] = 0; // 表示已经到达
        int d1, d2, d3;
        for (int T = TT - 1; T >= 0; T--)
            _rep(i, 1, n) {
            d1 = d[T + 1][i] + 1;
            d2 = INF, d3 = INF;
            if (i < n && has_train[T][i][0] && T + time[i] <= TT)
                d2 = d[T + time[i]][i + 1];
            if (i > 1 && has_train[T][i][1] && T + time[i - 1] <= TT)
                d3 = d[T + time[i - 1]][i - 1];
            d[T][i] = min(min(d1, d2), min(d1, d3));
        }

        printf("Case Number %d: ", ++kase);
        if (d[0][1] >= INF) printf("impossible\n");
        else printf("%d\n", d[0][1]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80740657