动态规划初步-单向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 }

 

posted @ 2018-08-07 18:06  Rogn  阅读(258)  评论(0编辑  收藏  举报