zoukankan      html  css  js  c++  java
  • 计蒜客 动态规划基础 蒜头君的城堡之旅

    规划基础 蒜头君的城堡之旅

    题目:

    蒜国地域是一个 n 行 m 列的矩阵,下标均从 1 开始。蒜国有个美丽的城堡,在坐标 (n,m) 上,蒜头君在坐标 (1,1) 的位置上。蒜头君打算出发去城堡游玩,游玩结束后返回到起点。在出发去城堡的路上,蒜头君只会选择往下或者往右走,而在返回的路上,蒜头君只会选择往上或者往左走,每次只能走一格。已知每个格子上都有一定数量的蒜味可乐,每个格子至多经过一次。
    现在蒜头君请你来帮他计算一下,如何计划来回行程,可以收集到最多的蒜味可乐。

    输入格式

    第一行输入两个整数 n,m(1≤n,m≤50),表示蒜国是一个 n 行 m 列的矩阵。
    接下来输入 n 行,每行输入 m 个整数,代表一个 n×m 的矩阵,每个整数代表对应位置上的蒜味可乐数量,每行的每两个整数之间用一个空格隔开。其中蒜头君的位置和城堡的位置上没有蒜味可乐,用 0 表示,其余位置上的整数范围在 [1,100] 内。

    输出格式

    输出一行,输出一个整数,表示蒜头君在来回路上能收集到的蒜味可乐的最大值。

    样例输入

    3 3
    0 2 9
    4 8 6
    2 7 0

    样例输出

    36

    分析:

    (可以理解为从起点出发的不相交的两条路径)
    首先,要注意一个问题:不能先算出去的最大值,再算返回的最大值。这样可能导致只保证了去的最大值,但没有保证来回之和的最大值。也就是说,来回的优先级是相同的,但是如果先算去路的最大值就会使得去的优先级高于回的优先级。
    容易注意到本题的范围不大,所以可以用一个四维数组: f[i][j][k][l] 来表示路径1走到 [i][j] 和路径2走到 [k][l] 的和的最优值。
    其中,因为走的步数相同,所以 i+j=k+l (可以利用这个等式来把空间和时间复杂度降一级),不难想到只要当前一步的两条路径没有走到用一个点,两条路径就不会相交(如果相交,重叠部分的可乐只能领取一次,就不是最优情况)。
    最后就不难写出动规方程:  f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]), max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))+map[i][j]+map[k][l]; 其中第一部分是求两个路径当前点的两个前趋情况的和的最大值(一共是 2×2 四种情况,所以用了一个 max 套两个 max)。
    最最后,因为两条路径在终点还是会交于一点,所以千万不能输出 f[n][m][n][m] ,应该输出 f[n-1][m][n][m-1] 。
     

    标程:

     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstring>
     4 using namespace std;
     5 int n,m,map[55][55],f[55][55][55][55];
     6 int main()
     7 {
     8     memset(f,0,sizeof(f));
     9     cin >> n >> m;
    10     for (int i=1; i<=n; i++)
    11     {
    12         for (int j=1; j<=m; j++)
    13         {
    14             cin >> map[i][j];
    15         }
    16     }
    17     for (int i=1; i<=n; i++)
    18     {
    19         for (int j=1; j<=m; j++)
    20         {
    21             for (int k=1; k<=n; k++)
    22             {
    23                 for (int l=1; l<=m; l++)
    24                 {
    25                     if (i+j!=k+l)
    26                         continue;
    27                     if (i==k && j==l)
    28                         continue;
    29                     f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]), max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))
    30                     +map[i][j]+map[k][l];
    31                 }
    32             }
    33         }
    34     }
    35     cout << f[n-1][m][n][m-1] << endl;
    36     return 0;
    37 }
  • 相关阅读:
    1393 0和1相等串 鸽笼原理 || 化简dp公式
    C. Coin Troubles 有依赖的背包 + 完全背包变形
    D. PolandBall and Polygon BIT + 欧拉公式
    51NOD 1639 绑鞋带 数学
    D. Fedor and coupons 二分暴力
    hdu 4104 Discount
    bnu 51640 Training Plan DP
    hdu 5745 La Vie en rose DP + bitset优化
    hdu 5036 Explosion bitset优化floyd
    1354 选数字 DP背包 + 数学剪枝
  • 原文地址:https://www.cnblogs.com/OIerPrime/p/7674569.html
Copyright © 2011-2022 走看看