洛谷 P1174 打砖块

题目描述

小红很喜欢玩一个叫打砖块的游戏,这个游戏的规则如下:

在刚开始的时候,有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表示没有。

所有的数与字符之间用一个空格隔开,行末没有多余的空格。

输出格式:

仅一个正整数,表示最大的得分。

输入输出样例

输入样例#1:
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
输出样例#1:
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



一开始觉得这就是一个分组背包,似乎不是,有点像子串那道题。
有借子弹的情况,预处理:sy[i][j],sn[i][j]表示第i列用j个子弹的得分,y表示最后一颗不是在i列打的,n表示是。
dp_n[i][j],dp_y[i][j]表示前i列一共消耗j颗子弹,最后一颗是否打在第i列上。

#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
const int N=205;
int n,m,k,sy[N][N],sn[N][N],a[N][N],dp_n[N][N],dp_y[N][N];
bool b[N][N];
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			char ch[11];
			scanf("%d%s",&a[i][j],ch);
			if(ch[0]=='Y')
				b[i][j]=1;
		}
	for(int i=1;i<=m;i++)
	{
		int cnt=0;
		for(int j=n;j>=1;j--)
			if(b[j][i])
				sy[i][cnt]+=a[j][i];
			else
				++cnt,sy[i][cnt]=sn[i][cnt]=sy[i][cnt-1]+a[j][i];
	}
	for(int i=1;i<=m;i++)//第i列 
		for(int j=0;j<=k;j++)//总共有j颗子弹 
			for(int g=0;g<=n&&g<=j;g++)//在第i列打出g颗 
			{
				dp_y[i][j]=max(dp_y[i][j],dp_y[i-1][j-g]+sy[i][g]);
				if(g>0)
					dp_n[i][j]=max(dp_n[i][j],dp_y[i-1][j-g]+sn[i][g]);//后打i列 
				if(j-g>0)
					dp_n[i][j]=max(dp_n[i][j],dp_n[i-1][j-g]+sy[i][g]);//先打i列 
			}
	printf("%d\n",dp_n[m][k]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值