zoukankan      html  css  js  c++  java
  • [HNOI 2004]敲砖块

    Description

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

    14 15  4  3  23
     33  33 76  2
       2   13 11
         22 23
           31

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

    你现在可以敲掉最多 m 块砖,求得分最多能有多少。

    Input

    输入文件的第一行为两个正整数 n 和m;接下来n 行,描述这n 层砖块上的分值a[i][j],满足0≤a[i][j]≤100。

    对于 100%的数据,满足1≤n≤50,1≤m≤n*(n+1)/2;

    Output

    输出文件仅一行为一个正整数,表示被敲掉砖块的最大价值总和。

    Sample Input

    4 5
    2 2 3 4
    8 2 7
    2 3
    49

    Sample Output

    19

    题解

    分析题目中的选取条件,我们会发现:
    这道题最终解的形态(选中的数字)可以描述成若干个三角形相互连接或重叠,如上图中的红色砖块,由两个蓝色标识的三角形部分重叠而成。
    将最终解的形态(选中的数字)的每列最下层点用线画出(图中的蓝线),可以发现:
    1、构成的轮廓线是一条锯齿状的折线;
    2、轮廓线上的相邻点布局在三角形的相列与相邻行上,即如果从左向右观察列,轮廓线上的点只能从其左列的上方行或下方行连过来;
    3、轮廓线上点所在列的上方点一定全部被选中。
    则把原问题转化为沟画出重叠三角形的锯齿状轮廓折线,找到一条合法的路径,使得围在轮廓线内的数字代价和最大。
    另,根据第 3 点分析,轮廓线上点所在列的上方点一定全部被选中,可将选中的数字压缩到轮廓线上点,问题进一步转化为求轮廓线上点的代价和最大。

    算法

    1、预处理:设 $cost[i,j]$表示选取第 $i$ 行第 $j$ 个,需要一起选取的其他点的个数。即与这个点同一列,且在这个点之上的点的个数。
    2、$sum[i,j]$表示选取第 $i$ 行第 $j$ 个,需要一起选取的其他点的数值和。即与这个点同一列,且在这个点之上的点的数值之和。这样,$cost[]$,$sum[]$分别记录了走到每个格子本列的数字个数与代价和。
    3、因为对于任意一列的任意一个数字,转移到它的前提与之前的方案无关,所以满足了$dp$ 的无后效性。 同时当前列必定要由之前的某个最优状态转移过来,所以又满足了最优子结构的性质。故 $DP$ 是可行的。

     1 //It is made by Awson on 2017.10.31
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <cstdio>
    10 #include <string>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define LL long long
    16 #define Max(a, b) ((a) > (b) ? (a) : (b))
    17 #define Min(a, b) ((a) < (b) ? (a) : (b))
    18 using namespace std;
    19 
    20 int n, m;
    21 int mp[55][55], cnt[55][55];
    22 int f[55][55][2505];
    23 
    24 void work() {
    25     scanf("%d%d", &n, &m);
    26     for (int i = 1; i <= n; i++) for (int j = 1; j <= n-i+1; j++) scanf("%d", &mp[i][j]);
    27     for (int i = 1; i <= n; i++)
    28     for (int j = 1; j <= n-i+1; j++) {
    29         if (i-2 >= 0) mp[i][j] += mp[i-2][j+1];
    30         cnt[i][j] = (i+1)/2;
    31     }
    32     memset(f, -1, sizeof(f));
    33     f[0][1][0] = 0; f[1][1][1] = mp[1][1];
    34     for (int y = 1; y <= n; y++)
    35     for (int x = 0; x <= n-y+1; x++)
    36         for (int k = 0; k <= m; k++)
    37         if (f[x][y][k] != -1) {
    38             f[x+1][y][k+cnt[x+1][y]] = Max(f[x+1][y][k+cnt[x+1][y]], f[x][y][k]+mp[x+1][y]);
    39             if (x == 0) f[x][y+1][k] = Max(f[x][y+1][k], f[x][y][k]);
    40             else f[x-1][y+1][k+cnt[x-1][y+1]] = Max(f[x-1][y+1][k+cnt[x-1][y+1]], f[x][y][k]+mp[x-1][y+1]);
    41         }
    42     printf("%d
    ", f[0][n+1][m]);
    43 }
    44 int main() {
    45     work();
    46     return 0;
    47 }
  • 相关阅读:
    JFinal连接多个数据库
    ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061) net start mysql服务名无效
    oracle中文显示为问号
    IDEA开发环境的设置约定
    WSL distro导入导出
    Linux服务器的x11图形模式方式远程管理参考
    WSL Linux 的 Windows 子系统[笔记]
    devops-cd之esxi和docker实战
    devops-cd之vagrant virtualbox实战
    ansible高级使用知识点
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7761749.html
Copyright © 2011-2022 走看看