打砖块
题目链接:http://acm.ocrosoft.com/problem.php?cid=1629&pid=51
题目描述:
小红很喜欢玩一个叫打砖块的游戏,这个游戏的规则如下:
在刚开始的时候,有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表示没有。
所有的数与字符之间用一个空格隔开,行末没有多余的空格。
对于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
输出
仅一个正整数,表示最大的得分。
样例输入
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
思路:先将输入的数据预处理,先求出每一列用ans颗子弹来打j列所能得到的最打分数,最后再用三层循环得出m行k颗子弹所能得到的最大分数。这里有一个坑点,碰到能加子弹的砖块时,你不一定能直接不加子弹直接加砖块的分数,如果你只有三颗子弹,加次数的砖块在第四个时,你就不能直接加第四块砖块的分数,所以就需要在代码中分两种情况处理。
代码:
#include<stdio.h>
int max(int x,int y)
{
if(x>y)
return x;
else
return y;
}
int main()
{
int n,m,k;
int score[205][205]={0};
int bullet[205][205]={0};
int dp[205][205]={0},dpy[205][205]={0};
int f[205][205]={0},fy[205][205]={0};
char t;
//输入
scanf("%d %d %d",&n,&m,&k);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scanf("%d %c",&score[i][j],&t);
if(t=='N')
bullet[i][j]=0;
else
bullet[i][j]=1;
}
}
//预处理,将第j列用不同数量的子弹所能获得分数的情况列出来
for(int j = 1; j <= m; j++)
{
//所用的子弹数量,每一列都置0
int ans = 0;
for(int i = n; i>0; i--)
{
//当前砖块打了能加子弹,相当于不用子弹直接得分
if(bullet[i][j])
dp[j][ans]+=score[i][j];
//不能加子弹,相当于用了一颗子弹,所以ans++
else
{
ans++;
//在没打子弹的基础上加上这轮打掉的砖块的分数
dp[j][ans] = dp[j][ans-1] + score[i][j];
dpy[j][ans] = dp[j][ans-1] + score[i][j];
}
}
}
for(int i = 1; i <= m; i++)
{
for(int j = 0; j <= k; j++)
{
for(int gg = 0;gg <= j&& gg <= n; gg++)
{
f[i][j]=max(f[i][j],f[i-1][j-gg]+dp[i][gg]);
if(gg != 0)
fy[i][j] = max(fy[i][j], f[i-1][j-gg] + dpy[i][gg]);// 后打当前列
if(j - gg > 0)
fy[i][j] = max(fy[i][j], fy[i-1][j-gg] + dp[i][gg]);//先打当前列
}
}
}
printf("%d\n",fy[m][k]);
return 0;
}