[动态规划] UVa116 单向TSP (多阶段决策问题)

题目

这里写图片描述

思路

多阶段图的最短路
1.本题中,每一列就是一个阶段,每个阶段都有3种决策:直行,右下和坐上。
2.状态定义:(i,j),出于第j列第i行。
3.指标函数:d(i,j),从格子(i,j)出发到最后一列的最短边权路。(最短边权路,是将格子数字大小作为边的权,即数字之和最小的路)
4.状态转移方程:

d ( i , j ) = m i n { d ( i + 1 , j + 1 ) , d ( i , j + 1 ) , d ( i 1 , j + 1 ) } + A [ i ] [ j ]

5.对于多阶段决策问题里,由于阶段就是天然的顺序,所以递推就好,没必要再用记忆化搜索。
6.本题输出解的时候,采用“递推顺带记录”的方法。

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#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 = 100 + 10;
int n, m, A[maxn][maxn], d[maxn][maxn], mynext[maxn][maxn];
// n:行数, m:列数

int main() {
    while (scanf("%d%d", &n, &m) == 2) {
        _rep(i, 1, n)
            _rep(j, 1, m)
                scanf("%d", &A[i][j]);

        int ans = INF, first = 0;
        for(int j = m-1; j>=0; j--)   // 阶段
            _rep(i, 1, n) {
                if (j == m - 1) d[i][j] = A[i][j+1];
                else {
                    int rows[3] = { i,i - 1,i + 1 };
                    if (i == 1) rows[1] = n;   // 因为矩阵是环形的
                    if (i == n) rows[2] = 1;
                    sort(rows, rows + 3);  // 因为要按字典序输出
                    d[i][j] = INF;
                    _for(k, 0, 3) {
                        int v = d[rows[k]][j + 1] + A[i][j+1];
                        if (v < d[i][j]) {
                            d[i][j] = v;
                            mynext[i][j] = rows[k];
                        }
                    }
                }   
                if (j == 0 && d[i][j] < ans) {
                    ans = d[i][j];
                    first = i;
                }
            }

        printf("%d", first);
        for (int i = mynext[first][0], j = 1; j < m; i = mynext[i][j], j++)
            printf(" %d", i);
        printf("\n%d\n", ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80753951
今日推荐