题目传送门
/*
题意:就是从上到下,找到最短路,输出路径
DP+路径:状态转移方程:dp[i][j] = min (dp[i-1][j], dp[i][j-1], dp[i][j+1]) + a[[i][j]; (类似数塔问题)
关键在记录路径,可以用pre[x][y] = -1/0/1/2 区分,DFS回溯输出
详细解释:http://www.cnblogs.com/staginner/archive/2012/05/02/2479658.html
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
const int MAXN = 1e2 + ;
const int MAXM = 5e2 + ;
const int INF = 0x3f3f3f3f;
int a[MAXN][MAXM];
int dp[MAXN][MAXM];
int pre[MAXN][MAXM];
void DFS(int x, int y)
{
if (pre[x][y] == -) {printf ("%d", y); return ;}
if (pre[x][y] == ) DFS (x-, y);
else if (pre[x][y] == ) DFS (x, y-);
else DFS (x, y+);
printf (" %d", y);
}
int main(void) //URAL 1029 Ministry
{
//freopen ("X.in", "r", stdin);
int n, m;
while (scanf ("%d%d", &n, &m) == )
{
memset (pre, -, sizeof (pre));
memset (dp, , sizeof (dp));
for (int i=; i<=n; ++i)
for (int j=; j<=m; ++j) scanf ("%d", &a[i][j]);
for (int i=; i<=m; ++i) {dp[][i] = a[][i]; pre[][i] = -;}
for (int i=; i<=n; ++i)
{
for (int j=; j<=m; ++j) {dp[i][j] = dp[i-][j] + a[i][j]; pre[i][j] = ;}
for (int j=; j<=m; ++j)
{
if (dp[i][j] > dp[i][j-] + a[i][j]) {dp[i][j] = dp[i][j-] + a[i][j]; pre[i][j] = ;}
}
for (int j=m-; j>=; --j)
{
if (dp[i][j] > dp[i][j+] + a[i][j]) {dp[i][j] = dp[i][j+] + a[i][j]; pre[i][j] = ;}
}
}
int mn = INF; int x = n; int y = ;
for (int i=; i<=m; ++i)
{
if (mn > dp[n][i]) {mn = dp[n][i]; y = i;}
}
//printf ("%d\n", mn);
DFS (x, y); puts ("");
}
return ;
}