敲砖块(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


题解:
首先我们将砖块向左对齐,变成一个直角三角形的形式,可以发现:
1. 每一列必须敲掉从第一行开始的从上到下的若干个砖块
2.如果某一列敲掉了K个砖块,那么其右边的那一列至少敲掉了K-1个砖块。
所以我们可以dp。
f[i][j][k]表示从右到左已经敲到了第I列,其中第I列敲掉了J个砖块且总共敲掉了K个砖块所得到的最大价值。
f[i][j][k]=max(f[i+1][v][k-j])+a[1][i]+..+a[1][j](v>=j-1)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 53
using namespace std;
int n,m;
int c[N][N],sum[N][N],f[N][N][N*10];
int main()
{
	freopen("brike.in","r",stdin);
	freopen("brike.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=n-i+1;j++)
	  scanf("%d",&c[i][j]);
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=n-i+1;j++)
	  sum[i][j]=sum[i][j-1]+c[j][i];
	memset(f,-1,sizeof(f));
	f[n+1][0][0]=0; int ans=0;
	for (int i=n;i>=1;i--)
	 for (int j=0;j<=n-i+1;j++)
	  for (int k=j;k<=m;k++)
	   for (int l=max(0,j-1);l<=n-i;l++)
	    if (k-j>=0&&f[i+1][l][k-j]!=-1) 
	    {
		  f[i][j][k]=max(f[i][j][k],f[i+1][l][k-j]+sum[i][j]);
		  ans=max(ans,f[i][j][k]);
	    }
	printf("%d\n",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值