• Luogu P1437 敲砖块


    题目大意

      在一个凹槽中放置了$n$层砖块,最上面的一层有$n$块砖,从上到下每层依次减少一块砖。每块砖都有一个分值,敲掉这块砖就能得到相应的分值,如图所示。

    Failed to load picture

      如果你想敲掉第$i$层的第$j$块砖的话,若$i=1$,你可以直接敲掉它,若$i>1$,则你必须先敲掉第$i-1$层的第$j$和第$j+1$块砖。

      你现在可以敲掉最多$m$块砖。输入$n$,$m$和这$n$层砖块($1 leqslant n leqslant 50$,$1 leqslant m leqslant 500$),求得分最多能有多少。

    题解

      我们可以想到,对于第$j$列的砖块,只与第$j$列和第$j + 1$列有关。如果我们用$(i,j)$表示第$i$层第$j$个砖块,那么敲掉$(i,j)$,就相当于敲掉$(1...i,j)$,然后再敲掉$(i - 1, j + 1)$。

      那我们可以从第$n$列到第$1$列进行dp,设$dp[i][j][k]$表示在第$j$到第$n$列,敲掉砖块第$i$层的第$j$个砖块,一共敲了$k$个砖快。容易得到状态转移方程

      $$dp[i][j][k] = sum_{i' = 1}^{i} a[i'][j] + underset{max {0, i - 1 } leqslant i' leqslant n - j}{max} { dp[i'][j + 1][k - i] }$$

      注意一下边界即可。

    #include <iostream>
    
    #define MAX_N (50 + 5)
    #define MAX_M (500 + 5)
    
    using namespace std;
    
    int n, m;
    int a[MAX_N][MAX_N];
    int dp[MAX_N][MAX_N][MAX_M];
    int mdp[MAX_N][MAX_N][MAX_M];
    int ans;
    
    int main()
    {
        cin >> n >> m;
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= n - i + 1; ++j)
            {
                cin >> a[i][j];
                a[i][j] += a[i - 1][j];
            }
        }
        for(int j = n; j; --j)
        {
            for(int i = n - j + 1; i >= 0; --i)
            {
                for(int k = (i + 1) * i / 2; k <= m; ++k)
                {
                    dp[i][j][k] = mdp[max(i - 1, 0)][j + 1][k - i] + a[i][j];
                    mdp[i][j][k] = max(mdp[i + 1][j][k], dp[i][j][k]);
                    ans = max(ans, dp[i][j][k]);
                }
            }
        }
        cout << ans;
        return 0;
    }
    参考程序
  • 相关阅读:
    Python学习笔记-常用内置函数
    Python练习-高阶函数-2018.12.03
    Python练习-生成器、迭代器-2018.12.01
    Python练习-列表生成式-2018.11.30
    Python练习-迭代-2018.11.28
    Python练习-循环及切片-2018.11.27
    FortiGate端口聚合配置
    FortiGate路由模式--静态地址线路上网配置
    方位电话批量配置教程
    Python学习笔记(七)
  • 原文地址:https://www.cnblogs.com/kcn999/p/11271963.html
Copyright © 2020-2023  润新知