P1174 打砖块

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<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 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的位置为i
41         //其实也就是贪心打掉最下层的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 }

时间: 2024-07-31 14:34:58

P1174 打砖块的相关文章

猫猫学IOS(十五)UI之曾经大热的打砖块小游戏

猫猫分享,必须精品 素材代码地址:http://blog.csdn.net/u013357243/article/details/44814523 原文地址:http://blog.csdn.net/u013357243?viewmode=contents !素材代码里面有我写的全部代码,注释齐全,方便学习 先看效果图 代码 //ps:新建iOS交流学习群:304570962 可以加猫猫QQ:1764541256 或则微信znycat 让我们一起努力学习吧. 原文:http://blog.csd

Codevs 1257 打砖块

1257 打砖块 http://codevs.cn/problem/1257/ 题目描述 Description 在一个凹槽中放置了n层砖块,最上面的一层有n块砖,第二层有n-1块,……最下面一层仅有一块砖.第i层的砖块从左至右编号为1,2,……i,第i层的第j块砖有一个价值a[i,j](a[i,j]<=50).下面是一个有5层砖块的例子.如果你要敲掉第i层的第j块砖的话,若i=1,你可以直接敲掉它,若i>1,则你必须先敲掉第i-1层的第j和第j+1块砖. 你的任务是从一个有n(n<=5

2015 IOS 学习笔记 打砖块练习以及接水果练习 ——蓝懿教育

今天我们进入做实例环节,刘国斌老师带我们做了两个小游戏,两个游戏看似简单但内包含的知识面几乎涵盖了之前所学到的所有东西,所以综合性很强,而且锻炼个人逻辑思维能力. 打砖块练习中,要再界面中添加一个砖块的矩形,两个控制砖块左右移动Button,然后在砖块之上建立一个球,使得界面开始时 球开始移动,然后碰撞到墙面反弹再碰撞反弹,直至反弹至砖块上?接住,使得球与砖块相交时再次反弹. 难点在于要考虑球反弹至墙壁后如何反弹,解决方法是给球设置一个移动速度speed,让这个speed是个数值类型,碰到墙壁,

打砖块(codevs 1257)

题目描述 Description 在一个凹槽中放置了n层砖块,最上面的一层有n块砖,第二层有n-1块,--最下面一层仅有一块砖.第i层的砖块从左至右编号为1,2,--i,第i层的第j块砖有一个价值a[i,j](a[i,j]<=50).下面是一个有5层砖块的例子.如果你要敲掉第i层的第j块砖的话,若i=1,你可以直接敲掉它,若i>1,则你必须先敲掉第i-1层的第j和第j+1块砖. 你的任务是从一个有n(n<=50)层的砖块堆中,敲掉(m<=500)块砖,使得被敲掉的这些砖块的价值总和

bzoj1112[POI2008]砖块Klo*

bzoj1112[POI2008]砖块Klo 题意: N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:丢掉某柱砖的一块砖.给某柱加上一块砖,现在希望用最小次数的动作完成任务.N≤100000 题解: 设一个区间长度为k,其中位数为a,比a小的元素个数为b,和为c:比a大的元素个数为d,和为e.则题目要求维护一个长度为k的滑动窗口,能求出它的b*a-c+e-d*a.故用一个维护sum,size两个值的treap来维护.然而似乎我想复杂了?比所有人代码都大1k!注意要开long

HNOI 2004 打砖块 动态规划

题意: 在一个凹槽中放置了n层砖块,最上面的一层有n块砖,第二层有n-1块,--,最下面一层仅有一块砖.第i层的砖块从左至右编号为1,2,--,i,第i层的第j块砖有一个价值a[i,j](a[i,j]<=50).下面是一个有5层砖块的例子: 如果要敲掉第i层的第j块砖的话,若i=1,可以直接敲掉它,若i>1,则必须先敲掉第i-1层的第j和第j+1块砖. 你的任务是从一个有n(n<=50)层的砖块堆中,敲掉(m<=500)块砖,使得被敲掉的这些砖块的价值总和最大. 方法:动态规划 解

IOS 开发入门—打砖块小游戏

忙着期末考试,读书笔记断更了~ ios 游戏处女作—demo 游戏规则 屏幕上方有四排砖块 点击屏幕开始游戏 游戏开始时,小球向上方运行 小球与砖块撞击可以撞碎砖块并反弹 小球与屏幕顶部.右侧.左侧碰撞会反弹 小球与挡板碰撞会反弹 左右移动手指可以挪动挡板 小球从屏幕下方掉出游戏结束 撞碎所有砖块游戏胜利 手机游戏的使用习惯 除非是非常出色的游戏或者游戏模式所迫,否则最好使用竖版的模式,适合用户单手操作手机,比较方便.而 iPad 则最好使用横版. 游戏类的屏幕一般要把手机上面的状态栏隐藏.不同

打砖块

1 // 2 // ViewController.m 3 // Blocks 4 // 5 // Created by apple on 13-7-5. 6 // Copyright (c) 2013年 itcast. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import <QuartzCore/QuartzCore.h> 11 12 @interface ViewController ()

BZOJ 1112: [POI2008]砖块Klo

1112: [POI2008]砖块Klo Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1736  Solved: 606[Submit][Status][Discuss] Description N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务. Input 第一行给出N,K. (1 ≤ k ≤ n ≤