设定状态 DP( i, j ) 表示从第一层到 i 层 j 房间 最小花费.
则状态转移方程为
DP( i, j ) = Max { DP( i-1,j), DP( i, j-1 ), DP( i, j+1 ) } + a( i , j )
因为 对于当前层的处理, 左右之间可以拆分开来处理,
再设定一个 d( i, j ) 记忆是由哪个位置走到当前位置的. 然后通过递归求路径即可
解题代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #include<stdlib.h> typedef long long LL; #define MAX(a,b) (a)>(b)?(a):(b) #define MIN(a,b) (a)<(b)?(a):(b) const LL inf = 1LL<<60; LL dp[110][510]; int a[110][510], d[110][510], n, m; void GetPath( int r, int c ) { if( r == 0 ){ printf("%d\n", c+1); return; } int x = d[r][c]/m, y = d[r][c]%m; GetPath(x, y); printf("%d\n", c+1); } int main() { while( scanf("%d%d", &n,&m) != EOF) { for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) { scanf("%d", &a[i][j] ); dp[i][j] = inf; } for(int i = 0; i < m; i++) { dp[0][i] = a[0][i]; d[0][i] = i; } for(int i = 1; i < n; i++) { dp[i][0] = dp[i-1][0]+a[i][0]; d[i][0] = (i-1)*m; for(int j = 1; j < m; j++) { if( dp[i][j] > (dp[i-1][j]+a[i][j] ) ) { dp[i][j] = dp[i-1][j]+a[i][j]; d[i][j] = (i-1)*m + j; } if( dp[i][j] > (dp[i][j-1]+a[i][j] ) ) { dp[i][j] = dp[i][j-1]+a[i][j]; d[i][j] = i*m + (j-1); } } for(int j = m-2; j >= 0; j-- ) { if( dp[i][j] > (dp[i][j+1]+a[i][j]) ) { dp[i][j] = dp[i][j+1]+a[i][j]; d[i][j] = i*m + (j+1); } } } LL Max = inf; int res; for(int i = 0; i < m; i++) { if( dp[n-1][i] < Max ) { Max = dp[n-1][i]; res = i; } } GetPath( n-1, res ); } return 0; }