打磚塊(codevs 1257)

題目描述  Description

在一個凹槽中放置了n層磚塊,最上面的一層有n塊磚,第二層有n-1塊,……最下面一層僅有一塊磚。第i層的磚塊從左至右編號爲1,2,……i,第i層的第j塊磚有一個價值a[i,j](a[i,j]<=50)。下面是一個有5層磚塊的例子。若是你要敲掉第i層的第j塊磚的話,若i=1,你能夠直接敲掉它,若i>1,則你必須先敲掉第i-1層的第j和第j+1塊磚。ios

 

你的任務是從一個有n(n<=50)層的磚塊堆中,敲掉(m<=500)塊磚,使得被敲掉的這些磚塊的價值總和最大。spa

 

 

 

輸入描述  Input Description

你將從文件中讀入數據,數據的第一行爲兩個正整數,分別表示n,m,接下來的第i每行有n-i+1個數據,分別表示a[i,1],a[i,2]……a[i,n – i + 1]。code

 

輸出描述  Output Description

輸出文件中僅有一個正整數,表示被敲掉磚塊的最大價值總和。blog

樣例輸入  Sample Input

4 5ip

2 2 3 4string

8 2 7io

2 3class

49stream

樣例輸出  Sample Output

19im

數據範圍及提示  Data Size & Hint

敲掉第一層的四塊磚,再敲掉第二層的第一塊磚,2+2+3+4+8=19

/*
    直接作DP多是很差作的,由於一個塊是否能被打,還取決於別的塊,也就是說,有後效性,那怎麼辦呢?
    咱們發現若是某個塊被打下來的話,它上面的全部的塊必定都被打下來了,因此咱們能夠將圖旋轉90°。
    設f[i][j][k]表示前i行(旋轉以後的行),選了j個,第i行選前k個的最大值。
    轉移方程:f[i][j][k]=max(f[i-1][j-p][p]+sum[i][k])(sum[i][k]是第i行選前k個的價值)。 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 60
using namespace std;
int a[N][N],sum[N][N],f[N][N*10][N],n,m;
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-1][i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            sum[i][j]=sum[i][j-1]+a[i][j];
    memset(f,-127/3,sizeof(f));
    f[0][0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=j;k++){
                for(int p=max(0,k-1);p<=i-1;p++)
                    f[i][j][k]=max(f[i-1][j-k][p]+sum[i][k],f[i][j][k]);
            }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int k=1;k<=m;k++)
            ans=max(ans,f[i][m][k]);
    printf("%d",ans);
    return 0;
}
相關文章
相關標籤/搜索