//如果只是使用一个状态f[i][j]记录最小值,那么为了使循环的时候保证无后效性,时间复杂度要是O(m*n^2),TLE,代码如下
//其实,为了保证路径左右不重复,只需要开Left[][],Right[][]数组就能使复杂度降到O(m*n);
//启始是通常可以通过增加维度使状态变得有序
//自己的做法还是很冗余,这位仁兄写的不错
http://www.chenyajun.com/2010/05/24/4871
#include <iostream> using namespace std; const int MAXN = 101; const int MAXM = 501; int main() { int i, j, n, m; int f[MAXN][MAXM]; //到达第 i 层第 j 个房间的最小费用 int fee[MAXN][MAXM]; int last[MAXN][MAXM]; //记录路径, last[i][j] 记录到达第 i 层第 j 个房间的上一个房间 scanf("%d %d", &n, &m); for(i = n; i >= 1; i--) for(j = 1; j <= m; j++) scanf("%d", &fee[i][j]); for(i = 1; i <= m; i++) { f[1][i] = fee[1][i]; last[1][i] = 0; } for(i = 2; i <= n; i++) { f[i][1] = f[i - 1][1] + fee[i][1]; last[i][1] = 1; f[i][m] = f[i - 1][m] + fee[i][m]; last[i][m] = m; for(j = 2; j <= m; j++) { //从左至右进行更驰 last[i][j] = j; f[i][j] = f[i - 1][j] + fee[i][j]; //从上到下 if(f[i][j] > f[i][j - 1] + fee[i][j]) { f[i][j] = f[i][j - 1] + fee[i][j]; last[i][j] = j - 1; } } for(j = m - 1; j >= 1; j--) { //从右至左进行更驰 if(f[i][j] > f[i][j + 1] + fee[i][j]) { f[i][j] = f[i][j + 1] + fee[i][j]; last[i][j] = j + 1; } } } int pre, minl; minl = f[n][1]; pre = 1; for(i = 2; i <= m; i++) { /* 到达第 n 层时对应的最小的 f[n][i] */ if(minl > f[n][i]) { minl = f[n][i]; pre = i; } } int c = n; while(pre) { printf("%d/n", pre); int next = last[c][pre]; if(next == pre) c--; //如果房间号next == pre说明是从上往下走的,故c减1 pre = next; } return(0); }