洛谷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表示没有。
所有的数与字符之间用一个空格隔开,行末没有多余的空格。
输出格式:
仅一个正整数,表示最大的得分。
输入输出样例
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
如果没有奖励子弹的话,相当于一个分组背包,决策每一列打几个就可以了。
↑50分解法
有奖励子弹的话,就有了特殊情况:例如某一列最下面有x个普通方块,其上面有一串奖励方块,要想拿到奖励方块,必须得预留x+1颗子弹,这多出来的1颗子弹可以在以后用来打之前某列的砖块。
所以需要多一维状态,处理留一发子弹/不留的情况。
状态多了有些迷茫,半抄着题解写完……我已经是条咸鱼了。
f1是留一发子弹的状态,f2是都打完的状态。
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mxn=220; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 int f1[mxn][mxn],f2[mxn][mxn];//[列][使用子弹数]=最优解 17 int n,m,k; 18 int mp[mxn][mxn]; 19 bool re[mxn][mxn]; 20 int w1[mxn][mxn],w2[mxn][mxn]; 21 void init(){ 22 for(int j=1;j<=m;j++){ 23 int cnt=n; 24 while(cnt && re[cnt][j]){ 25 w1[j][0]+=mp[cnt][j]; 26 cnt--; 27 } 28 for(int i=1;i<=n && cnt ;i++){//打了i发子弹 29 w2[j][i]=w1[j][i-1]+mp[cnt][j]; 30 w1[j][i]=w2[j][i]; 31 cnt--; 32 while(cnt && re[cnt][j]){ 33 w1[j][i]+=mp[cnt][j]; 34 cnt--; 35 } 36 } 37 } 38 return; 39 } 40 int main(){ 41 n=read();m=read();k=read(); 42 int i,j; 43 for(i=1;i<=n;i++) 44 for(j=1;j<=m;j++){ 45 mp[i][j]=read(); 46 char ch=getchar(); 47 if(ch=='N')re[i][j]=0; 48 else re[i][j]=1; 49 } 50 init(); 51 /* 52 for(i=1;i<=n;i++){ 53 for(j=1;j<=m;j++){ 54 printf("%5d %5d ",mp[i][j],num[i][j]); 55 } 56 printf("\n"); 57 }*/ 58 for(i=1;i<=m;i++){//列 59 for(j=0;j<=k;j++){//子弹 60 for(int l=0;l<=j;l++){//之前已用子弹 61 f1[i][j]=max(f1[i][j],f1[i-1][j-l]+w1[i][l]); 62 if(l<j){ 63 f2[i][j]=max(f2[i][j],f2[i-1][j-l]+w1[i][l]); 64 } 65 if(l){ 66 f2[i][j]=max(f2[i][j],f1[i-1][j-l]+w2[i][l]); 67 } 68 } 69 } 70 } 71 printf("%d\n",f2[m][k]); 72 return 0; 73 }