zoukankan      html  css  js  c++  java
  • 【codevs1257】 打砖块

    http://codevs.cn/problem/1257/ (题目链接)

    题意

      在等腰三角形上打砖块,总共有m发炮弹,每块砖有一个权值,求打出的最大权值

    Solution 

      今天考试题,考场上的2个小时就此荒废了,1班是毛戏了。。看来dp还是有待提高,是时候多做做题了。 

      此题一看就是dp对吧,就算不知道看了标签也知道了吧= =。我们把三角变成一个直角三角,于是我们发现,若要打第i列的第j个砖块,那么必须至少打掉第i+1列的前j-1个砖块以及第i列的前j-1个砖块,而打掉第i+1列前j-1个砖块就必须至少打掉第i+1列前j-2个砖块以及第i+2列前j-2个砖块……这样递归下去,形状大概长这样: 
      这里写图片描述 
      比如说我们要打掉第1列第3行的4,我们就必须先打掉以(2,2)为顶点的三角形和一个矩形,如果有更多的子弹,那么就可以打掉以(2,3)为顶点的三角形中的一些点,前提是第2列从1到3都被打掉。也就是说要打掉第i列第j行的砖块,只与第i+1列的砖块有关。 

      于是我们可以写出dp方程。用a[i][j]表示从第i列的第1行到第j行的权值和,用f[i][j][k]表示打掉第i列第j行的砖块,已经打掉了k个。所以方程:f[i][j][k]=max(f[i][j][k],f[i+1][p][k-j]+a[j][i]),p=[]。 

      但是我们还要考虑一种情况,就拿上面那幅图来说吧,如果我们有4发子弹,那么答案是多少呢?打掉第一行的第1、2、4块和第二行第1块是最优的,答案为16。我们发现这个最优答案它并不是由上面我们所说的那样第i列第j行的答案只与后一列有关,它是间断的。 
      这里写图片描述 
      怎么处理呢?我们可以再加入一行:第0行,第0行用来记录不取当前第i列中的砖块,直接取第i-1列中的砖块所得到的最大值,而这个并不与之前的dp方程矛盾,所以就做出来了。

    代码

    // codevs1257
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    inline int getint() {
        int f,x=0;char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1;else f=1;ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
        return f*x;
    }
    
    const int maxn=100;
    int n,m;
    int a[maxn][maxn],f[maxn][maxn][600],t[maxn];
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n-i+1;j++) {scanf("%d",&a[i][j]);a[i][j]+=a[i-1][j];}
        for (int i=1;i<=n;i++) t[i]=t[i-1]+i;
        t[0]=1;int ans=0;
        for (int i=n;i>=1;i--)
            for (int j=0;j<=n-i+1;j++) {
                for (int k=t[j];k<=m;k++)
                    for (int p=max(0,j-1);p<=n-i+1;p++)
                        f[i][j][k]=max(f[i][j][k],f[i+1][p][k-j]+a[j][i]);
                ans=max(ans,f[i][j][m]);
                }
        printf("%d",ans);
        return 0;
    }
    

      

  • 相关阅读:
    [leetcode]存在重复
    [leetcode]旋转数组
    git使用方法(持续更新)
    [LeetCode]从排序数组中删除重复项
    Communications link failure--分析之(JDBC的多种超时情况)
    云主机挂载磁盘
    hadoop对于压缩文件的支持
    linux 转移mysql文件操作流程
    MindManager2018 修改过期时间 配置文件路径
    Innodb 中 RR 隔离级别能否防止幻读?
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5914288.html
Copyright © 2011-2022 走看看