题目传送: UVA - 116
思路:可以定义状态为dp[i][j] 为从第i行第j列开始往后走到第n列(总共n列)的最小值(赋初始值为无穷),且状态方程很好推出来:dp[i][j] = a[i][j] + max(dp[i-1][j+1], dp[i][j+1], dp[i+1][j+1]); 最后最优解 ans = max(dp[i][1])(1<=i<=m);
不过这题难点不在这里,而是可能有多组最小值,输出字典序最小的那组;
这里要注意好递推的方向,只能从右往左递推列数,而如果从左往右递推则不能满足字典序
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;
LL dp[15][105];
int a[15][105];
int beh[15][105];
int n, m;
int main() {
while(scanf("%d %d", &m, &n) != EOF) {
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
scanf("%d", &a[i][j]);
dp[i][j] = INF;
}
}
memset(beh, 0, sizeof(beh));
for(int i = 1; i <= m; i++) {
dp[i][n] = a[i][n];
}
for(int j = n - 1; j >= 1; j--) {
for(int i = 1; i <= m; i++) {
for(int k = -1; k <= 1; k++) {
int t = i + k;
if(t == 0) t = m;
else if(t == m + 1) t = 1;
if(a[i][j] + dp[t][j+1] < dp[i][j]) {
dp[i][j] = a[i][j] + dp[t][j+1];
beh[i][j] = t;
}
else if(a[i][j] + dp[t][j+1] == dp[i][j] && t < beh[i][j]) {
beh[i][j] = t;
}
}
}
}
int ans = INF, ansi, ansj = 1;
for(int i = 1; i <= m; i++) {
if(dp[i][1] < ans) {
ans = dp[i][1];
ansi = i;
}
}
while(1) {
if(beh[ansi][ansj] == 0) {
printf("%d\n", ansi);
break;
}
printf("%d ", ansi);
ansi = beh[ansi][ansj];
ansj ++;
}
printf("%d\n", ans);
}
return 0;
}