P1174 打砖块 题解
Harry_Hedwig · · 题解
0x00 思路
此题让我十分的销魂(销魂:极度悲伤)
先看题。
小红很喜欢玩一个叫打砖块的游戏,这个游戏的规则如下在刚开始的时候,有
n 行\times m 列的砖块,小红有k 发子弹。小红每次可以用一发子弹,打碎某一列当前处于这一列最下面的那块砖,并且得到相应的得分。某些砖块在打碎以后,还可能将得到一发子弹的奖励。最后当所有的砖块都打碎了,或者小红没有子弹了,游戏结束。小红在游戏开始之前,就已经知道每一块砖在打碎以后的得分,并且知道能不能得到一发奖励的子弹。小红想知道在这次游戏中她可能的最大得分,可是这个问题对于她来说太难了,你能帮帮她吗?
回答问题:不能。看完题目会有一个明显的区间 dp 思路,我们很明显可以定义一个 dp 数组来存储前
0x01 初始化
由于我们需要用到每一列用
coding
注:(非最终答案)
for(i=1;i<=m;i++)//列
{
for(j=1,w=n;j<=k&&w>0;j++,w--)//子弹未消耗完(j),砖块未打完(w)
{
if(c[w][i]=='Y')//Y不消耗子弹
sum[i][--j]+=f[w][i];
else
sum[i][j]=sum[i][j-1]+f[w][i];
}
}
好了,这个初始化出来了你就可以得一些分了(全是
只想得部分分的同学可直接跳转0x02。
那么为了得
3 3 3
1 Y 1 Y 1 Y
1 N 1 N 1 N
1 Y 1 Y 1 Y
你会发现如果你的初始化是如上的初始化时,你的程序会输出
原因很简单,当你在打最后一块砖(一定是
为了得到满分,可以思考
那么为了防止冷不丁在这一列中出现
code
注:最终代码
for(i=1;i<=m;i++)
{
for(j=1,w=n;j<=min(n,k)&&w>0;j++,w--)//j,w意义同上
{
if(c[w][i]=='Y') //根据前文,dy为最后打'Y',dn为最后打'N'
dy[i][--j]+=f[w][i];
else
dy[i][j]=dy[i][j-1]+f[w][i],dn[i][j]=dy[i][j];
}
}
0x02 区间 dp
仍然分
定义数组 dp[i][j] : 用
那么由于是区间 dp,所以假设用了
coding
for(i=1;i<=m;i++)//第i列
{
for(j=1;j<=k;j++)//前i列共用j颗子弹
{
for(l=0;l<=j;l++)//当前列使用的子弹数
dp[i][j]=max(dp[i-1][l]+sum[i][j-l],dp[i][j]);
}
}
(对于部分分)End
你会发现你根本没有办法得满分(状态转移如上的话),于是你就会再次思考:子弹打在
由于打
仍然是
那么我们里面的状态转移就会发生改变:先定义
根据我们上面的推论,这里就有
-
没打完。
更新
dp1 。code:
dp1[i][j]=max(max(dp2[i-1][j-l],dp1[i-1][j-l])+dy[i][l],dp1[i][j]);注:
-
-
用完了
-
在这一列用了第
j 颗子弹前提是有条件(即你在这一行用了子弹)
code:
if(l>0) dp2[i][j]=max(dp2[i][j],dp1[i-1][j-l]+dn[i][l]); -
不在这一列用了第
j 颗子弹前提是你没有在这一列用了全部的子弹
code:
if(l<j) dp2[i][j]=max(dp2[i][j],dp2[i-1][j-l]+dy[i][l]);注:
-
在最后输出的时候输出 你本来就只有 )
结束语
说实话,这道题挺恶心的,因为它的思维量很大,所以很难去想怎么做。就给你一种:我知道它是区间 dp,但是就是做不出来的无奈心情。
但是不得不说,这个 dp 题真的挺好,不做可惜了QWQ。
(代码就不用给了吧……都已经放题解里了……)