博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P1174 打砖块
阅读量:6577 次
发布时间:2019-06-24

本文共 4274 字,大约阅读时间需要 14 分钟。

P1174 打砖块

【P1174】打砖块 - 洛谷

https://www.luogu.org/problem/show?pid=1174

 

题目描述

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

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

 

 分析:

 参考:

P1174 打砖块 – XBCoder

http://blog.qbudg.link/?p=845

 

这题难点在于,砖块分成两种N,Y,否则就是一个简单的线性DP了

  1. 首先贪心,对于最下层的所有Y(能直接打掉的)我们都直接打掉
  2. 预处理,我们需要处理3个数组:now[j][i]代表第j列我们要打第i个砖块可以得到的分数,注意,如果第i个砖块上有Y,要把Y也加到now里面。。。第二个数组res[j][i],这个是个前缀和,表示第j列我们要打第i个砖块的得分(这个和now的区别在于如果i砖块上面有Y也不加进去)。。。第三个数组ci[j][i]表示第j列我们要打第i个砖块需要多少子弹
  3. DP方程:DP[j][k][0]表示不从后面借子弹时前j列用k颗子弹能得到的最大分数,DP[j][k][1]表示借子弹时的最大分数。。。这里解释下借子弹:比如第一列是 2 Y 2 N ,所以N必须先打掉,那么dp[1][1][0]=2,dp[1][1][1]=4。注意这里借子弹要还回去,所以借子弹的情况必须是打Y砖
  4. 转移方程:
    dp[j][k][0]=max(dp[j][k][0],max(dp[j-1][k-ci[j][i]][1],dp[j-1][k-ci[j][i]][0])+res[j][i]); //这里很好理解的,就是前面j-1列(找第j列借子弹)借或不借,但是当前第j列不去找别人借子弹,所以借能打掉的都打不掉,所以是res[j][i]
    dp[j][k][0]=max(dp[j][k][0],dp[j-1][k-ci[j][i]][0]+now[j][i]);
    // 这里其实是前面不找第j列借,但是当前第j列可以不找后面借子弹,但是第j列可以找前面借子弹,所以能打掉的都打掉,所以是now[j][i]
    dp[j][k][1]=max(dp[j][k][1],dp[j-1][k-ci[j][i]][1]+now[j][i]);
    // 这里其实是前面找第j列借,但是当前第j列可以找后面借子弹
  5. 注意初始化哦:for(j=0;j<=m;j++) dp[j][0][0]=-inf;

 

 

1 #include
2 #include
3 #include
4 #include
5 #include
6 #define ll long long 7 #define M(a) memset(a,0,sizeof a) 8 #define fo(i,j,k) for(i=j;i<=k;i++) 9 using namespace std;10 const int mxn = 205;11 int n, m, p, ans;12 char ch;13 int a[mxn][mxn], whe[mxn], res[mxn][mxn];14 int dp[mxn][mxn][2], ci[mxn][mxn], now[mxn][mxn]; //0:不需要借,1:需要借 15 bool b[mxn][mxn];16 int main()17 {18 int i, j, k;19 scanf("%d%d%d", &n, &m, &p);20 //子弹为0,直接输出 21 if (p == 0) { printf("0\n"); return 0; }22 //a[i][j]表示打掉第i行j列位置的砖块的得分23 //b[i][j] = 1表示打掉第i行j列位置的砖块可以奖励一颗子弹 24 //读数据的时候按行翻转了,就是上下翻转了 25 for (i = n; i >= 1; i--)26 fo(j, 1, m)27 {28 scanf("%d", &a[i][j]);29 cin >> ch;30 if (ch == 'Y') b[i][j] = 1;31 }32 //贪心打掉最下层的Y ,因为这里上下翻转了,所以打掉的是上层的 33 fo(j, 1, m)//j列 34 {35 fo(i, 1, n)//i行 36 {37 if (!b[i][j]) break;38 ans += a[i][j];39 }40 //因为上下翻转了,whe[j]=i表示第j列第一个N的位置为i41 //其实也就是贪心打掉最下层的Y之后剩下的N 42 whe[j] = i;43 }44 //now[j][i]代表第j列我们要打第i个砖块可以得到的分数,注意,如果第i个砖块上有Y,要把Y也加到now里面 45 //res[j][i],这个是个前缀和,表示第j列我们要打第i个砖块的得分(这个和now的区别在于如果i砖块上面有Y也不加进去)46 fo(j, 1, m) fo(i, whe[j], n) res[j][i] = res[j][i - 1] + a[i][j];47 fo(j, 1, m) fo(i, whe[j], n) now[j][i] = res[j][i];48 //ci[j][i]表示第j列我们要打第i个砖块需要多少子弹 49 //修正now[j][i]数组和填充ci[j][i]数组 50 fo(j, 1, m)51 {52 ci[j][whe[j]] = 1;53 fo(i, whe[j], n)54 {55 int tmp = i;56 //b[i + 1][j]对应的为Y 57 //这部分理解可以画个小图 58 while (b[i + 1][j]) i++;59 now[j][tmp] = res[j][i];60 ci[j][i + 1] = ci[j][tmp] + 1;61 }62 }63 //初始值 前j列在不借子弹的情况下用0发子弹打 64 fo(j, 0, m) dp[j][0][0] = -1e8;65 66 fo(j, 1, m)67 fo(k, 1, p)68 {69 dp[j][k][0] = max(dp[j][k][0], dp[j - 1][k][0]);70 dp[j][k][1] = max(dp[j][k][1], dp[j - 1][k][1]);71 fo(i, whe[j], n) if (!b[i][j] && k >= ci[j][i])72 {73 dp[j][k][0] = max(dp[j][k][0], max(dp[j - 1][k - ci[j][i]][1], dp[j - 1][k - ci[j][i]][0]) + res[j][i]);74 dp[j][k][0] = max(dp[j][k][0], dp[j - 1][k - ci[j][i]][0] + now[j][i]);75 dp[j][k][1] = max(dp[j][k][1], dp[j - 1][k - ci[j][i]][1] + now[j][i]);76 }77 }78 printf("%d\n", dp[m][p][0] + ans);79 return 0;80 }
View Code

 

转载于:https://www.cnblogs.com/Renyi-Fan/p/7476659.html

你可能感兴趣的文章
saltstack-haproxy安装
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
小程序正式上线啦,我们采访了最早内测它的人和首批小程序
查看>>
python中的集合
查看>>
基于Kerberos的Windows Network Authentication
查看>>
pnp4nagios的安装
查看>>
Linux启动过程详解
查看>>
线程与进程
查看>>
js倒计时
查看>>
艰难快乐运维路----之cacti的安装与配置(一)
查看>>
paramiko
查看>>
Linux用户和组管理命令总结
查看>>
samba服务的搭建
查看>>
我的友情链接
查看>>
centos系统中了一次毒(哇咔咔)DoS:Linux/Xorddos!rfn
查看>>
无线路由器WDS设置方法图解(无线桥接设置)【炮哥】
查看>>
Mysql问题集合。。。
查看>>
网络传输控制
查看>>
如何配置mugo自动下围棋
查看>>