题目链接:https://vjudge.net/problem/UVA-116
一个格子可以往它上一行的后一个格子,本行的后一个格子和下一行的后一个格子走,找出花费最少的路径,输出路径上每列的行号, 多解输出字典序最小。
思路:
多阶段决策问题,状态的定义不难看出:d[i][j]:从(i,j)出发到最后一列的最短距离。
关键是如何输出“字典序”最小的路径:只需要在求d[i][j](最优)的时候记录下由那个转移过来的,顺序还是逆序枚举列都可以,顺序枚 举只是多了一个逆序输出的过程。
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#define ll long long
#define pq priority_queue
using namespace std;
const int maxn = 1e5 + 10;
int n,m;
int a[105][105], dp[105][105], nextt[105][105], rows[105];
int main()
{
while(scanf("%d%d", &n, &m)!=EOF)
{
int maxx = 0x3f3f3f3f;
int first;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scanf("%d", &a[i][j]);
if(j == m)
dp[i][j] = a[i][j];
else
dp[i][j] = 0x3f3f3f3f;
}
}
for(int i = m-1; i >= 1; i--) //列
{
for(int j = 1; j <= n; j++)
{
int row[3] = {j-1, j, j+1};
if(j == 1)
row[0] = n;
if(j == n)
row[2] = 1;
sort(row, row+3);
for(int k = 0; k < 3; k++)
{
int ans = dp[row[k]][i+1] + a[j][i];
if(ans < dp[j][i])
{
dp[j][i] = ans;
nextt[j][i] = row[k];
}
}
if(i == 1 && dp[j][i] < maxx)
{
first = j;
maxx = dp[j][i];
}
}
}
if(m==1)
{
for(int i = 1; i <= n;i++)
{
if(maxx > a[i][1])
{
maxx = a[i][1];
first = i;
}
}
}
printf("%d",first);
for(int i = nextt[first][1], j = 2; j <= m; i = nextt[i][j],j++)
printf(" %d", i);
printf("\n%d\n", maxx);
}
return 0;
}