POJ1038 Bugs Integrated, Inc.
题目来源:http://poj.org/problem?id=1038
题目大意:
有一家芯片公司要在一块N*M的板子上嵌入芯片,其中1<=N<=150, 1<=M<=10,但是板子上有一些格子是坏的,不能放置芯片。芯片的面积是2*3,可以横着放也可以竖着放,但不能有重叠。如下图所示:
现给出N M和坏点的坐标,求最多能在板子上嵌入多少芯片。
输入:第一行测试用例数,每例第一行三个整数N、M和K,K为坏点数。接下来K行,每行一个坏点坐标(n,m),1<=n<=N,1<=m<M,0<=K<=N*M.
输出:每组输入对应一行,输出能嵌入的最大芯片数目。
Sample Input
2
6 6 5
1 4
4 6
2 2
3 6
6 4
6 5 4
3 3
6 1
6 2
6 4
Sample Output
3
4
对于没有过竞赛经验的算法弱菜来说,这题是目前为止耗费掉了最多脑细胞的题,看了题解的”状态压缩DP“,小菜表示闻所未闻,实在太高级了,汗颜。结合网上看的解题报告和”黑书“里面的各种晦涩讲解,把自己理解的一种解题思路(更准确的说是解题方法吧,因为这思路我现在看来也是神一般的)写在下面吧:
黑书上说:观察后发现,N和M的范围相去甚远,同时总数据规模较大。这就给与提示:此题很可能是需要信息加密的动态规划,即把一行看成一个整体。
[画外音:第一,对于我这种弱菜来说,显然没有感受到这种”很可能“;第二,该书整文中对行列的描述与图片与题目图片里的行列方向是不一样的,但是题目里面给出的坐标的x和y的表示是x->N, 表行号,y->M,表列号,加上网上结题报告各种行列的错乱让小菜一开始晕头转向@_@... 所以,在本文中,为了尽量避免再出现这样的问题,辛苦读者在大脑中把上面的图逆时针旋转90°,约定M表示列数,N表示行数,方向(旋转后)约定为左->右,列号1->M,下->上,行号1->N.]
好了,回到重点。由于芯片的尺寸为2*3,所以我们能否在板子上放置一块芯片,使得该芯片的左上角所在格子的坐标为[x,y],只与[x, y]所在行和与它相邻的下面两行的占用状态(包括是否为坏点和是否被芯片占用两种情况)有关。由此启发,为每个格子设计一个状态表示方法(共三种状态,如图所示),来表示对它上一行相邻的格子能够作为芯片左上角位置的影响。
设当前格为[x,y],
0:表示[x,y]和[x,y-1]都为空闲
1:表示[x,y]空闲, [x,y-1]被占用(为坏点或者被其它芯片占用)
2:表示[x,y]被占用,此时无论[x,y-1]是否被占用,[x,y+1]处的格子都不可能成为某块芯片的左上角,所以不用管它的占用情况了
设计好了单个格子的状态表示之后,为了进行状态压缩,把一行中表示各个格子的状态值(第i列的格子状态值称p[i])组成的序列(看成是一个三进制串p[1]p[2]...p[M])换算成一个10进制数state,用来表示这一行的状态。一行有M格,每格有3种可能的状态,那么一行总共有3^M种状态。M的最大值为10,所以,一行最多的状态数为3^10=59049。
设计好了行的状态表示,接下来需要设计dp的状态和状态转移方程(各种状态@_@).
二维dp表中dp[i][j]表示当第i行的状态为j时,前i行放置芯片的最大数量。0<=i<=N, 0<=j<=3^M. 这样,就可以用当前行的状态推出上一行的放置情况(因为行状态j已经包含了两行格子的状态信息,所以有dp[i]足以推出dp[i+1]的信息, 这是后面使用滚动数组的基础)。
初始时把dp表的所有元素初始化为-1,表示该状态不可达或尚未开始考虑。
由一行的各列格子状态推出上一行的该列格子状态的规律是:q[i] = (p[i] == 0 ? 0 : p[i]-1); (q表示相邻上一行的格子的状态,分别试试三种情况就知道了)此时,还没有考虑上一行是否遇到坏点,所以当上一行这一列遇到了坏点,则q[i]应该变为2.
接下来是状态转移方程,考虑格子[i, y]时,有三种情况:
1. [i,y]不放芯片,转到[i,y+1];
2. [i,y]放纵向芯片,需要纵向的6个空格,所以条件为p[y] == 0 && p[y+1] == 0 && q[y] == 0 && q[y+1] == 0,更新dp[i+1][j'],j'为放了该块芯片后的i+1行状态,转到[i,y+2];
3. [i,y]放横向芯片,需要横向的6个空格,所以条件为y+2 <= M && q[y] == 0 && q[y+1] == 0 && q[y+2] == 0,更新dp[i+1][j'],j'为放了该块芯片后的i+1行状态,转到[i,y+3];
至此,dp的过程已经介绍完了(不知道讲清楚了几成=_=b),另外的一点优化就是上面提到的由于dp表一行一行更新时不需要前面更多行的信息,所以可以使用滚动数组来压缩存储,即循环利用数组的空间。
另一个优化在于:基于”加快经常性事件“的思想,本题里3进制和10进制的转换是频繁事件,选择高效的转换方法可以大大提高程序效率,由于位数确定且较少,可以预先计算好各位的权重。
//////////////////////////////////////////////////////////////////////////
// POJ1038 Bugs Integrated, Inc.
// Memory: 720K Time: 969MS
// Language: C++ Result: Accepted
////////////////////////////////////////////////////////////////////////// #include <iostream> using namespace std; int N, M, k;
int d[][];
int w[] = {, , , , , , , , , , , };
int p[];
int q[];
int badSquares[][];
int cnt;
int o; inline int ternary2decimal(int a[]) {
int sum = ;
for (int i = ; i <= M; ++i) {
sum += a[i] * w[i];
}
return sum;
}
inline void decimal2ternary(int code, int a[]) {
for (int i = ; i <=M; ++i) {
a[i] = code % ;
code /= ;
}
} void dfs(int p[], int q[], int y, int cntNow) {
int qState = ternary2decimal(q);
if (cntNow > d[ - o][qState]) {
d[ - o][qState] = cntNow;
}
if (cntNow > cnt) {
cnt = cntNow;
}
for (int t = y; t < M; ++t) {
if (q[t] == && q[t + ] == && p[t] == && p[t + ] == ) {
q[t] = q[t + ] = ; //放置一块纵向芯片
dfs(p, q, t + , cntNow + ); //转至右边第二块
q[t] = q[t + ] = ;
} else if (t + <= M && q[t] == && q[t + ] == && q[t + ] == ) {
q[t] = q[t + ] = q[t + ] = ; //放置一块横向芯片
dfs(p, q, t + , cntNow + ); //转至右边第三块
q[t] = q[t + ] = q[t + ] = ;
}
}
} int main(void) {
int cases;
cin >> cases;
while(cases--) {
cin >> N >> M >> k;
memset(d, -, sizeof(d));
memset(badSquares, , sizeof(badSquares));
for (int i = ; i < k; ++i) {
int x, y;
cin >> x >> y;
badSquares[x][y] = ;
}
for (int i = ; i <= M; ++i) {
p[i] = badSquares[][i] + ;
//预先处理第一行的状态,坏点为2,
//好点为1(可以看做人工加入了全部是坏点的第0行,
//省去了下边界处理的问题)
}
d[][ternary2decimal(p)] = ; //前0行可放芯片数0
o = ;
cnt = ;
for (int i = ; i < N; ++i) {
memset(d[ - o], -, sizeof(d[ - o]));
for (int j = ; j < w[M + ]; ++j) {
if (d[o][j] == -) {
continue;
}
decimal2ternary(j, p);
for (int k = ; k <= M; ++k) {
q[k] = p[k] == ? : p[k] - ; //推上一行的每格状态
if (badSquares[i + ][k] == ) {
q[k] = ; //遇上坏点,状态为2
}
}
dfs(p, q, , d[o][j]);
}
o = - o;
}
printf("%d\n", cnt);
}
system("pause");
return ;
}
POJ1038 Bugs Integrated, Inc.的更多相关文章
- POJ1038 - Bugs Integrated, Inc.(状态压缩DP)
题目大意 要求你在N*M大小的主板上嵌入2*3大小的芯片,不能够在损坏的格子放置,问最多能够嵌入多少块芯片? 题解 妈蛋,这道题折腾了好久,黑书上的讲解看了好几遍才稍微有点眉目(智商捉急),接着看了网 ...
- POJ1038 Bugs Integrated, Inc 状压DP+优化
(1) 最简单的4^10*N的枚举(理论上20%) (2) 优化优化200^3*N的枚举(理论上至少50%) (3) Dfs优化状压dp O(我不知道,反正过不了,需要再优化)(理论上80%) (4) ...
- poj1038 Bugs Integrated,Inc. (状压dp)
题意:N*M的矩阵,矩阵中有一些坏格子,要在好格子里铺2*3或3*2的地砖,问最多能铺多少个. 我的方法好像和网上流传的方法不太一样...不管了.... 由数据范围很容易想到状压dp 我们设某个状态的 ...
- POJ-1038 Bugs Integrated, Inc. (状压+滚动数组+深搜 的动态规划)
本题的题眼很明显,N (1 <= N <= 150), M (1 <= M <= 10),摆明了是想让你用状态压缩dp. 整个思路如下:由于要填2*3或者3*2的芯片,那么就要 ...
- POJ 1038 Bugs Integrated, Inc.(DFS + 三进制状压 + 滚动数组 思维)题解
题意:n*m方格,有些格子有黑点,问你最多裁处几张2 * 3(3 * 2)的无黑点格子. 思路:我们放置2 * 3格子时可以把状态压缩到三进制: 关于状压:POJ-1038 Bugs Integrat ...
- Bugs Integrated, Inc.
Bugs Integrated, Inc. 给出一个\(n\times m\)的矩形网格图,给出其中K个障碍物的位置,求其中最多能摆的\(2\times 3\)的矩形的个数,\(n\leq 150,m ...
- 【CEOI2002】【Poj 1038】Bugs Integrated, Inc.
http://poj.org/problem?id=1038 发一下中文题面(今天考试直接被改了): 生记茶餐厅由于受杀人事件的影响,生意日渐冷清,不得不暂时歇业.四喜赋闲在家,整天抱着零食看电视,在 ...
- POJ 1038 Bugs Integrated Inc (复杂的状压DP)
$ POJ~1038~~\times Bugs~Integrated~Inc: $ (复杂的状压DP) $ solution: $ 很纠结的一道题目,写了大半天,就想练练手,结果这手生的.其实根据之前 ...
- POJ 1038 Bugs Integrated, Inc.
AC通道 神坑的一道题,写了三遍. 两点半开始写的, 第一遍是直接维护两行的二进制.理论上是没问题的,看POJ discuss 上也有人实现了,但是我敲完后准备开始调了.然后就莫名其妙的以为会超时,就 ...
随机推荐
- 2018.06.29 洛谷P2890 [USACO07OPEN]便宜的回文(简单dp)
P2890 [USACO07OPEN]便宜的回文Cheapest Palindrome 时空限制 1000ms / 128MB 题目描述 Keeping track of all the cows c ...
- 2018.09.16 bzoj1086: [SCOI2005]王室联邦(贪心)
传送门 就是给树分块. 对于一个节点. 如果它的几棵子树加起来超过了下限,就把它们分成一块. 这样每次可能会剩下几个节点. 把它们都加入栈中最顶上那一块就行了. 代码: #include<bit ...
- 自学如何去学习jQuery
学习JQ第一个demo: 制作一个轮播图,制作方法我前面写了一篇博客,传送门-->http://www.cnblogs.com/yewenxiang/p/6100206.html 需要的JQ知识 ...
- HDU 1061 Rightmost Digit (快速幂取模)
题意:给定一个数,求n^n的个位数. 析:很简单么,不就是快速幂么,取余10,所以不用说了,如果不会快速幂,这个题肯定是周期的, 找一下就OK了. 代码如下: #include <iostrea ...
- 深入浅析JavaScript中with语句的理解
JavaScript 有个 with 关键字, with 语句的原本用意是为逐级的对象访问提供命名空间式的速写方式. 也就是在指定的代码区域, 直接通过节点名称调用对象. with语句的作用是暂时改变 ...
- SPSS-比较均值-独立样本T检验 案例解析
在使用SPSS进行单样本T检验时,很多人都会问,如果数据不符合正太分布,那还能够进行T检验吗?而大样本,我们一般会认为它是符合正太分布的,在鈡型图看来,正太分布,基本左右是对称的,一般具备两个参数,数 ...
- Codeforces801C Voltage Keepsake 2017-04-19 00:26 109人阅读 评论(0) 收藏
C. Voltage Keepsake time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- hdu 1300 Deck
题目 分析:对于n张卡片的最佳摆法,我们只需要在n-1张卡片的摆法下面加一张边缘与桌檐重合的卡片,并将所有卡片一起向桌檐外移动.对于一种最佳摆法,其中心一定在桌檐上,所以一定符合杠杆原理,支点是桌檐. ...
- hdu 5038 求出现次数最多的grade
http://acm.hdu.edu.cn/showproblem.php?pid=5038 模拟水题 求出现次数最多的grade.如果有多个grade出现的次数一样多,且还有其他的grade,则把这 ...
- visual studio code 中隐藏从 ts 文件生成的 js 文件和 map 文件
typescript 文件编译产生的 js 和 map 文件不需要手工编辑,打开[文件][首选项][工作区设置],放入以下代码: // 将设置放入此文件中以覆盖默认值和用户设置. { "fi ...