【codevs 1257】【NOIP 模拟题】[HNOI 2004] 敲砖块(dp)
敲砖块
【题目描述】
在一个凹槽中放置了N层砖块,最上面的一层油N块砖,从上到下每层一次减少一块砖。每块砖都有一个分支,敲掉这块砖就能得到相应的分值,如图所示。
如果你想敲掉第i层的第j块砖的话,若i=1,你可以直接敲掉它;若i>1,则你必须先敲掉第i-1层的第j和第j+1块砖。
你现在可以敲掉最多M块砖,求得分最多能有多少。
【输入文件】
输入文件的第一行有两个正整数N和M;
接下来的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;
}
既然无能更改,又何必枉自寻烦忧