A Spy in the Metro UVA-1025(dp)

vjudge链接

原题链接

  • 分析

我的第一个动归题哈哈,一开始甚至写成了 dfs 。动归题其实都可以用 dfs ,但是太多的重复计算会导致超时。这个题其实可以以时间为主线,通过两层循环填表来解决。紫书上是逆推的,其实顺推和逆推都可以,逆推更方便。

刚开始以为 “Trainsmove in both directions: from the first station to the last station and from the last station back to the first station.” 是说车到达终点站后会折返,事实上只是说两个方向的车行驶方向不同而已。车到达终点站后不会折返。

  • AC 代码

顺推:

/*
 *lang C++ 5.3.0
 *user Weilin_C
*/
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

int main()
{
    int N, T, station[50], c = 0;
    int rightT[205][25], leftT[205][25], tr, tl;
    int dp[500][50];

    while (scanf("%d", &N) && N) {
        int t;
        memset(rightT, 0, sizeof(rightT));
        memset(leftT, 0, sizeof(leftT));
        scanf("%d", &T);
        for (int i = 0; i < N-1; i++)
            scanf("%d", &station[i]);
            scanf("%d", &tr);
            for (int i = 0; i < tr; i++) {
                scanf("%d", &t);
                for (int ti = t, st = 0; ti <= T && st < N; st++) {
                    rightT[ti][st] = 1;
                    ti += station[st];
                }
            }
            scanf("%d", &tl);
            for (int i = 0; i < tl; i++) {
                scanf("%d", &t);
                for (int ti = t, st = N-1; ti <= T && st > 0; st--) {
                    leftT[ti][st] = 1;
                    ti += station[st-1];
                }
            }

            //初始化为比 T 大就行,也可以用 memset(dp, 1, sizeof(dp));
            for (int i = 0; i <= T; i++)
                for (int j = 0; j <= N; j++)
                    dp[i][j] = T+1;

            dp[0][0] = 0;
            for (int i = 1; i <= T; i++) {
                for (int j = 0; j < N; j++) {
                    dp[i][j] = dp[i-1][j] + 1;
                    if (j > 0 && i >= station[j-1] && rightT[i-station[j-1]][j-1]) { //有右向车到达
                        dp[i][j] = min(dp[i][j], dp[i-station[j-1]][j-1]);
                    }
                    if (j < N-1 && i >= station[j] && leftT[i-station[j]][j+1]) { //有左向车到达
                        dp[i][j] = min(dp[i][j], dp[i-station[j]][j+1]);
                    }
                }
            }

            printf("Case Number %d: ", ++c);
            if (dp[T][N-1] > T) printf("impossible\n");
            else printf("%d\n", dp[T][N-1]);
    }

    return 0;
}

逆推和紫书上差不多:

            dp[T][N-1] = 0;
            for (int i = T-1; i >= 0; i--) {
                for (int j = 0; j < N; j++) {
                    dp[i][j] = dp[i+1][j] + 1;
                    if (j < N-1 && i + station[j] <= T && rightT[i][j]) { //有右向车出发
                        dp[i][j] = min(dp[i][j], dp[i + station[j]][j+1]);
                    }
                    if (j > 0 && i + station[j-1] <= T && leftT[i][j]) { //有左向车出发
                        dp[i][j] = min(dp[i][j], dp[i + station[j-1]][j-1]);
                    }
                }
            }

            printf("Case Number %d: ", ++c);
            if (dp[0][0] > T) printf("impossible\n");
            else printf("%d\n", dp[0][0]);

by SDUST weilinfox
原文链接:https://www.cnblogs.com/weilinfox/p/12559058.html

posted @ 2020-03-24 14:56  桜風の狐  阅读(128)  评论(0编辑  收藏  举报