在一個凹槽中放置了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
你將從文件中讀入數據,數據的第一行爲兩個正整數,分別表示n,m,接下來的第i每行有n-i+1個數據,分別表示a[i,1],a[i,2]……a[i,n – i + 1]。code
輸出文件中僅有一個正整數,表示被敲掉磚塊的最大價值總和。blog
4 5ip
2 2 3 4string
8 2 7io
2 3class
49stream
19im
敲掉第一層的四塊磚,再敲掉第二層的第一塊磚,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; }