打砖块(game.pas/c/cpp)
【题目描述】
小红很喜欢玩一个叫打砖块的游戏,这个游戏的规则如下:
在刚开始的时候,有n行*m列的砖块,小红有k发子弹。小红每次可以用一发子弹,打碎某一列当前处于这一列最下面的那块砖,并且得到相应的得分。
如图所示:
某些砖块在打碎以后,还可能将得到一发子弹的奖励。最后当所有的砖块都打碎了,或者小红没有子弹了,游戏结束。
小红在游戏开始之前,就已经知道每一块砖在打碎以后的得分,并且知道能不能得到一发奖励的子弹。小红想知道在这次游戏中她可能的最大得分,可是这个问题对于她来说太难了,你能帮帮她吗?
【输入格式】
第一行有3个正整数,n,m,k。表示开始的时候,有n行*m列的砖块,小红有k发子弹。
接下来有n行,每行的格式如下:
f1 c1 f2 c2 f3 c3 …… fm cm
其中fi为正整数,表示这一行的第i列的砖,在打碎以后的得分。ci为一个字符,只有两种可能,Y或者N。Y表示有一发奖励的子弹,N表示没有。
所有的数与字符之间用一个空格隔开,行末没有多余的空格。
【输出格式】
仅一个正整数,表示最大的得分。
【输入样例】
3 4 2
9 N 5 N 1 N 8 N
5 N 5 Y 5 N 5 N
6 N 2 N 4 N 3 N
【输出样例】
13
【数据规模】
对于20%的数据,满足1<=n,m<=5,1<=k<=10,所有的字符c都为N
对于50%的数据,满足1<=n,m<=200,1<=k<=200,所有的字符c都为N
对于100%的数据,满足1<=n,m<=200,1<=k<=200,字符c可能为Y
对于100%的数据,所有的f值满足1<=f<=10000
算法:DP
很值得思考的一个问题,我觉得是很有深度的一道题。
首先对于Y这个特殊情况(打一次附赠一次子弹),我们可以证明其实用1发子弹我们就相当于1发子弹都没用,假设当前子弹为x发,那么x-1+1=x,所以对于Y这种情况我们可以作连续累计的。
【题目描述】
小红很喜欢玩一个叫打砖块的游戏,这个游戏的规则如下:
在刚开始的时候,有n行*m列的砖块,小红有k发子弹。小红每次可以用一发子弹,打碎某一列当前处于这一列最下面的那块砖,并且得到相应的得分。
如图所示:
某些砖块在打碎以后,还可能将得到一发子弹的奖励。最后当所有的砖块都打碎了,或者小红没有子弹了,游戏结束。
小红在游戏开始之前,就已经知道每一块砖在打碎以后的得分,并且知道能不能得到一发奖励的子弹。小红想知道在这次游戏中她可能的最大得分,可是这个问题对于她来说太难了,你能帮帮她吗?
【输入格式】
第一行有3个正整数,n,m,k。表示开始的时候,有n行*m列的砖块,小红有k发子弹。
接下来有n行,每行的格式如下:
f1 c1 f2 c2 f3 c3 …… fm cm
其中fi为正整数,表示这一行的第i列的砖,在打碎以后的得分。ci为一个字符,只有两种可能,Y或者N。Y表示有一发奖励的子弹,N表示没有。
所有的数与字符之间用一个空格隔开,行末没有多余的空格。
【输出格式】
仅一个正整数,表示最大的得分。
【输入样例】
3 4 2
9 N 5 N 1 N 8 N
5 N 5 Y 5 N 5 N
6 N 2 N 4 N 3 N
【输出样例】
13
【数据规模】
对于20%的数据,满足1<=n,m<=5,1<=k<=10,所有的字符c都为N
对于50%的数据,满足1<=n,m<=200,1<=k<=200,所有的字符c都为N
对于100%的数据,满足1<=n,m<=200,1<=k<=200,字符c可能为Y
对于100%的数据,所有的f值满足1<=f<=10000
算法:DP
很值得思考的一个问题,我觉得是很有深度的一道题。
首先对于Y这个特殊情况(打一次附赠一次子弹),我们可以证明其实用1发子弹我们就相当于1发子弹都没用,假设当前子弹为x发,那么x-1+1=x,所以对于Y这种情况我们可以作连续累计的。
具体解释见代码。
program game;
const
maxn=200;
var
n,m,tot:longint;
f,by,bn,sy,sn:array [0..maxn,0..maxn] of longint;{四个数组,f[i,j]表示第i行第j列的砖块的分数,by[i,j]表示前i列总共用了j发子弹获得的最大值(注意这里是总共用了子弹的数目),bn[i,j]表示前i列实际用了j发子弹获得的最大值(实际用了表示有多少用了多少),sy[i,j]表示第i列前j行获得额外子弹的分数,sn[i,j]表示不获得额外子弹的分数。}
{因为这四个数组不太容易理解,所以在这里说明一下。}
c:array [0..maxn,0..maxn] of char;
procedure init;
var
i,j,st:longint;
ch:char;
begin
readln(n,m,tot);
for i:=1 to n do
begin
for j:=1 to m do read(f[i,j],ch,c[i,j]);
readln;
end;
for i:=1 to m do
begin
st:=n;
while (st>0) and (c[st,i]='Y') do{这里sy[i,0]相当于一发子弹都没有用,因为打一发就获得一发。}
begin
inc(sy[i,0],f[st,i]);
dec(st);
end;
for j:=1 to n do
begin
if st>0 then
begin
sn[i,j]:=sy[i,j-1]+f[st,i];
sy[i,j]:=sn[i,j];
dec(st);
while (st>0) and (c[st,i]='Y') do{同理,连续的Y实际上一发子弹都没有浪费。}
begin
inc(sy[i,j],f[st,i]);
dec(st);
end;
end;
end;
end;
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y);
end;
procedure main;
var
i,j,k:longint;
begin
for i:=1 to m do
begin
for j:=0 to tot do
begin
for k:=0 to n do
begin
if k<=j then{这里是总限制,如果打掉前k行,那么子弹必须小于等于用过的子弹。}
begin
by[i,j]:=max(by[i,j],by[i-1,j-k]+sy[i,k]);{这里不做限制,因为我们表示的都是获得了额外子弹的那个分数,而打额外子弹不需要任何耗费。}
if k<j then bn[i,j]:=max(bn[i,j],bn[i-1,j-k]+sy[i,k]);{实际用的子弹必须大于0。}
if k>0 then bn[i,j]:=max(bn[i,j],by[i-1,j-k]+sn[i,k]);{同上。}
end;
end;
end;
end;
end;
begin
assign(input,'game.in'); reset(input);
assign(output,'game.out'); rewrite(output);
init;
main;
writeln(bn[m,tot]);{最后输出的也是实际上用掉的子弹。}
close(input); close(output);
end.
本文深入探讨了打砖块游戏中的策略选择与得分最大化问题,通过动态规划算法解决,详细解析了如何利用游戏规则,特别是针对特殊砖块(如Y型砖块)的得分累积与额外子弹获取机制,最终实现最优得分策略。
1032

被折叠的 条评论
为什么被折叠?



