UVA116 Unidirectional TSP

一. Vjudge链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?OJId=UVA&probNum=116

二. 题目大意:给一个矩阵,让你从左边走到右边,每次只能走右,右上,右下。从第一行走右上到最后一行,从最后一行走右下到第一行,求最小的路径长度(每次走过一个格子,路径增加格子里面的数),并输出最小字典序的路径(从第一列到最后一列关于行的路径)。

三. 思路:本来以为是DP水题,3个状态,上中下取最小,扫一遍就完了,没想到它弄了个字典序最小输出,这里指的是先比较第一个,再比较第二个。因此一定要从后向前扫,每次取最小,不能从前向后扫。(这个不知道为什么,留待以后补充。)因为它是环形的,2条路最小值一样,其中一条全部往右走,如果有一条路从第一个跳到了最后一个的话,从前往后扫会取那条中间的路,但是这样是错误的,因为会比较先输出的,因此要取那条跳到最后一个的路。

四. 代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>

using namespace std;

const int MAX_N = 128,
          MAX_M = 15,
          INF = 0x3f3f3f3f;

int dp[MAX_M][MAX_N], row, col,
    Next[MAX_M][MAX_N];

int getMin(int i, int j)
{
    j = j+1;//注意我一进入就加上1,以后不用重复写
    int up, mid, down, idx, res;

    mid = i;
    up = (i-1 == 0? row:i-1);
    down = (i+1 > row? 1:i+1);
    idx = INF;

    if(dp[mid][j] <= dp[up][j] && dp[mid][j] <= dp[down][j])
        res = dp[mid][j], idx = min(idx, mid);

    if(dp[up][j] <= dp[mid][j] && dp[up][j] <= dp[down][j])
        res = dp[up][j], idx = min(idx, up);

    if(dp[down][j] <= dp[mid][j] && dp[down][j] <= dp[up][j])
        res = dp[down][j], idx = min(idx, down);


    Next[i][j-1] = idx;

    return res;
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int i, j;
    while(~scanf("%d %d", &row, &col)){
        for(i = 1; i <= row; i++)
            for(j = 1; j <= col; j++)
                scanf("%d", &dp[i][j]);

        for(j = col-1; j >= 1; j--)
            for(i = 1; i <= row; i++)
            dp[i][j] += getMin(i, j);

        int res = INF, idx;
        for(i = 1; i <= row; i++)
            if(res > dp[i][1])
                res = dp[i][1], idx = i;

        printf("%d", idx);
        for(i = 1; i < col; i++){
            idx = Next[idx][i];
            printf(" %d", idx);
        }

        printf("\n%d\n", res);
    }

    return 0;
}



你可能感兴趣的:(UVA116 Unidirectional TSP)