向前走莫回头❤

【codevs 1257】【NOIP 模拟题】[HNOI 2004] 敲砖块(dp)

敲砖块

【题目描述】

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

 

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

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

【输入文件】

  输入文件的第一行有两个正整数NM

  接下来的N行,描述这N层砖块上的分值A[i,j],满足0<=A[i,j]<=100

【输出文件】

    仅一行,包含一个整数,为最大的得分。

【样例输入】

    4 5

    2 2 3 4

    8 2 7

    2 3

    49

【样例输出】

    19

【数据规模】

  对于20%的数据,满足1<=N<=10,1<=M<=30

  对于100%的数据,满足1<=N<=50,1<=M<=500

————————————————————————————————
【题解】【dp】
【f[i][j][k]表示从右到左敲到第i行,其中第i行敲了j块砖,共敲了k块砖】
【转移方程:f[i][j][k]=max{f[i][j][k-j],f[i][j][k]+a[v][i]…a[1][i]}】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[60][60],f[60][60][510];
int n,m,ans;
int main()
{
	freopen("brike.in","r",stdin);
	freopen("brike.out","w",stdout);
	int i,j,k,l;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	 for(j=1;j<=n-i+1;++j)
	  scanf("%d",&a[i][j]);
	memset(f,128,sizeof(f));
	f[n+1][0][0]=0;
	for(i=n;i>0;--i)
	 for(j=0;j<=n-i+1;++j)
	  for(k=j;k<=m;++k)
	   {
	   	for(l=j-1;l<=n-i;++l)
	   	 {
	   	 	if(l<0&&f[i+1][n+1][k-j]>f[i][j][k]) f[i][j][k]=f[i+1][n+1][k-j];
	   	 	if(l>=0&&f[i+1][l][k-j]>f[i][j][k]) f[i][j][k]=f[i+1][l][k-j];
			}
		for(l=1;l<=j;++l) f[i][j][k]+=a[l][i];
		if(f[i][j][k]>ans) ans=f[i][j][k];
	   }
	printf("%d\n",ans);
	return 0;  
}


posted @ 2016-08-25 16:58  lris0-0  阅读(126)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m