HDU 1619 Unidirectional TSP (单向旅行商问题)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1619

题目大意:找出从最左边到最右边的权值最小的一条路(起点可以是最左边的任意一点,终点同理),如果有多条,输出字典序最小的那一条的路径(只需要输出在第几行)和权值。

注意:只能向右,右上方,右下方前进,第一行可以到达最后一行,最后一行也能到第一行。

思路:动态规划,用数组来储存下一步的行数,dp记录到(i,j)的最小路径,逆向使用DP。

参考代码:

#include 
#include 
#include 

#define INF 1e9

using namespace std;


int m, n, a[12][104], dp[12][104], b[12][104];      //m行n列,a是每点的数值,b是路径
  
int main()
{
    while (scanf("%d%d", &m, &n) != EOF) {
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                scanf("%d", &a[i][j]);
            }
            dp[i][n - 1] = a[i][n - 1];      
        }
        int ans = INF;
        for (int j = n - 1; j >= 0; --j) {      //逆向使用DP
            for (int i = 0; i < m; ++i) {
                dp[i][j] = INF;
                int j1 = j + 1;
                int row[3] = { i - 1,i,i + 1 };
                if (row[0] < 0)row[0] = m - 1; if (row[2] == m)row[2] = 0;      //注意!
                sort(row, row + 3);      //使字典序最小
                for (int k = 0; k < 3; ++k) {
                    int temp = dp[row[k]][j + 1] + a[i][j];
                    if (dp[i][j] > temp) {
                        dp[i][j] = temp;
                        b[i][j] = row[k];
                    }
                }
            }
        }
        int s;      //初始行数
        for (int i = 0; i < m; ++i)
            if (dp[i][0] < ans) {
                ans = dp[i][0];   
                s = i;   
            }
        printf("%d", s + 1);     
        for (int i = 0; i < n - 1; ++i) {
            printf(" %d", b[s][i] + 1);
            s = b[s][i];
        }
        printf("\n%d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(HDU)