动态规划初步-单向STP
一、题目
给一个m行n列(m <= 10,n <= 100)的整数矩阵,从第一列任何位置出发每次往右、右下、右上走一格,最终达到最后一列。要求经过的整数之和最小。整个矩阵是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行。输路径上每一列的行号及路径上的整数和,多解时输出字典序最小的。
二、解题思路
我们按列考虑,从最后一列开始,每一列可以由前一列决定,设dp[i][j]表示由格子(i,j)到最后一列的最小开销。于是有dp[i][j] = max(dp[i][j + 1],dp[i - 1][j + 1],dp[i +1][j + 1])。把最后一列初始化为其本身,从右至左可得到每一列的情况,取第一列中的最小即可。由于要输出路径,用nextpos[i][j]记录在j+1列时选取的行坐标。字典序的处理见代码注释。
三、代码实现
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 7 const int INF = 0x3f3f3f3f; 8 const int maxm = 10 + 10; 9 const int maxn = 100 + 10; 10 int maze[maxm][maxn],dp[maxm][maxn]; //dp[i][j]表示从(i,j)出发到最后一列的最小值 11 int nextpos[maxn][maxn]; //nextpos[i][j]记录在j+1列时选取的行坐标 12 int m, n; 13 14 void slove() 15 { 16 int ans = INF, first = 0; 17 for (int j = n - 1; j >= 0; j--) //从右至左 18 { 19 for (int i = 0; i < m; i++) 20 { 21 if (j == n - 1) dp[i][j] = maze[i][j]; //边界 22 else 23 { 24 int rows[3] = {i,i - 1,i+1}; 25 if (i == 0) rows[1] = m - 1; //注意考虑m = 1、2 26 if (i == m - 1) rows[2] = 0; 27 sort(rows, rows + 3); //保证字典序最小 28 dp[i][j] = INF; 29 for (int k = 0; k < 3; k++) 30 { 31 int tmp = dp[rows[k]][j + 1] + maze[i][j]; 32 if (tmp < dp[i][j]) 33 { 34 dp[i][j] = tmp; 35 nextpos[i][j] = rows[k]; //dp更新,nextpos也会更新,这保证了nextpos记录的是最优路径 36 } 37 } 38 } 39 if (j == 0 && dp[i][j] < ans) 40 { 41 ans = dp[i][j]; 42 first = i; 43 } 44 } 45 } 46 47 printf("%d", first + 1); 48 for (int i = nextpos[first][0],j = 1; j < n; j++) 49 { 50 printf(" %d", i + 1); 51 i = nextpos[i][j]; 52 } 53 printf("\n%d\n", ans); 54 } 55 56 int main() 57 { 58 while (scanf("%d%d",&m,&n) == 2) 59 { 60 for (int i = 0; i < m; i++) 61 for (int j = 0; j < n; j++) 62 scanf("%d", &maze[i][j]); 63 64 slove(); 65 } 66 return 0; 67 }
个性签名:时间会解决一切