• 动态规划初步-单向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("
    %d
    ", 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 }
  • 相关阅读:
    C++继承 派生类中的内存布局(单继承、多继承、虚拟继承)
    Linux 共享库(动态库)
    虚幻4
    从头认识java-16.5 nio的数据转换
    JavaScript实现禁用键盘和鼠标的点击事件
    Codeforces Round #277.5 (Div. 2)部分题解
    iOS-WKWebView使用
    我学cocos2d-x (三) Node:一切可视化对象的祖先
    Android Studio右下角不显示当前branch名称
    Neo4j简单的样例
  • 原文地址:https://www.cnblogs.com/lfri/p/9438558.html
Copyright © 2020-2023  润新知