• [HNOI2004]敲砖块


    题目描述

    在一个凹槽中放置了 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 块砖,求得分最多能有多少。

    输入输出格式

    输入格式:

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

    0≤a[i][j]≤100。

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

    输出格式:

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

    输入输出样例

    输入样例#1:
    4 5
    2 2 3 4
    8 2 7
    2 3
    49
    输出样例#1:
    19

    题解:
    讲讲我是怎么搞对的吧...
    2 2 3 4
    8 2 7
    2 3
    49
    看样例这个图,会发现一行一行dp会存在后效性,那么不妨试着竖着dp
    然后发现一个性质:如果(i,j)选了那么(1,j)到(i-1,j)就必须都选 后一列(1,j+1)到(i-1,j+1)也是
    那么就发现类似于捆绑背包的方法去做了,一行必须捆起来把前i位都打掉.
    然后就开始作死.......这tm实在是写着烦啊
    然后看题解发现可以旋转过来
    4
    3 7
    2 2 3
    2 8 2 49
    这样就变成了前i行和前j列的dp.
    可以设状态为F[i][j][k]表示 前i行 第i行选了j个,一共选了k个的最大价值
    好处理多了......
    注意边界条件一堆........
     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #define RG register
     8 using namespace std;
     9 const int N=55;
    10 int a[N][N],f[N][N][1550],sum[N][N];
    11 void work()
    12 {
    13     int n,m;
    14     scanf("%d%d",&n,&m);
    15     for(int i=1;i<=n;i++)
    16         for(int j=1,tmp=n-i+1;j<=tmp;j++)
    17             scanf("%d",&a[n-j+1][i]);
    18     for(int i=1;i<=n;i++)
    19         for(int j=1;j<=i;j++)
    20             sum[i][j]=sum[i][j-1]+a[i][j];
    21     int ans=0,p;
    22     for(int i=1;i<=n;i++)
    23         for(RG int g=0,lim=min(((i+1)*i)>>1,m);g<=lim;g++)
    24            for(RG int j=0,tmp=min(i,g);j<=tmp;j++){
    25                 for(RG int k=max(j-1,0),tmper=min(g-j,i-1);k<=tmper;k++){
    26                     p=f[i-1][k][g-j]+sum[i][j];
    27                     if(p>f[i][j][g])f[i][j][g]=p;
    28                 }
    29             }
    30       for(int j=0;j<=n;j++)
    31         if(f[n][j][m]>ans)ans=f[n][j][m];
    32     printf("%d
    ",ans);
    33 }
    34 
    35 int main()
    36 {
    37     work();
    38     return 0;
    39 }
    
    
    
     
  • 相关阅读:
    小数据池与编码新知
    你确定自己用过字典?
    Django基础三之视图函数
    Django基础二之URL路由系统
    Django基础一之web框架的本质
    CSS
    前端HTML
    MySQL创建用户和授权
    MySQL之索引原理
    Mysql之视图,触发器,事物,存储过程,函数
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7289953.html
Copyright © 2020-2023  润新知