UVa 116 - Unidirectional TSP

传送门

UVa 116 - Unidirectional TSP

题意

给一个图,最后一行向下走是第一行,第一行向上走是最后一行。要求从左边走到右边,数字之和最小,如果有相同的和,输出字典序最小的行数。

思路

参考了LRJ入门经典第二版。
因为要是字典序最小,所以要从后面往前推。然后依次算出每一列的最小值,直到第一列,然后根据记录的路径输出。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 2147483647;

int dp[20][110], Next[20][110], mp[20][110];

int main()
{
    //freopen("input.txt", "r", stdin);
    int m, n, i, j;
    while (~scanf("%d%d", &m, &n))
    {
        memset(dp, 0, sizeof(dp));
        for (i = 0; i < m; i++)
            for (j = 0; j < n; j++)
                scanf("%d", [i][j]);
        int ans = INF, first = 0;
        for (int j = n - 1; j >= 0; j--)
        {
            for (int i = 0; i < m; i++)
            {
                if (j == n - 1)
                    dp[i][j] = mp[i][j];
                else
                {
                    int row[] = {i, i - 1, i + 1};
                    if (i == 0)
                        row[1] = m - 1;
                    if (i == m - 1)
                        row[2] = 0;
                    sort(row, row + 3); //确保行数最小。
                    dp[i][j] = INF;
                    for (int k = 0; k < 3; k++)
                    {
                        int temp = dp[row[k]][j + 1] + mp[i][j];
                        if (temp < dp[i][j])
                        {
                            dp[i][j] = temp;
                            Next[i][j] = row[k];
                        }
                    }
                }
                if (j == 0 && dp[i][j] < ans)
                {
                    ans = dp[i][j];
                    first = i;
                }
            }
        }
        printf("%d", first + 1);
        for (i = Next[first][0], j = 1; j < n; i = Next[i][j], j++)
            printf(" %d", i + 1);
        printf("\n%d\n", ans);
    }
    return 0;
}

Powered by Jekyll and Theme by solid