二进制示例(二进制枚举(三))
下面继续通过几个示例体会二进制枚举方法的应用 。
【例1】建造碉堡
问题描述
设有一个街道笔直的方形城市 。该城市的地图是一个有n行和n列的正方形 ,每行代表一条街道或一堵墙 。
碉堡是一座有四个开口的小城堡 ,可以通过这些开口射击 。四个开口分别面向北 、东 、南和西 。每个开口都会有一支机枪射击 。
假设一颗子弹威力巨大 ,它可以穿越任何距离 ,并在途中摧毁一座碉堡 。另一方面 ,一堵墙是如此坚固 ,可以阻挡子弹 。
你的目标是在该城市中建造尽可能多的碉堡 ,建造的碉堡要求任意两座碉堡都不会互相摧毁 。也就是说没有两个碉堡位于同一水平行或垂直列上 ,除非至少有一堵墙将它们隔开 。
例如 ,图1(a)是没有建造碉堡的初始初始状态(图中正方形黑块代表墙);图1(b)和(c)是建造可行方案(图中黑色实心圆代表建造的碉堡) ,图1(d)和(e)是建造不可行的方案 。对图1(a)所示的城市状态 ,最多可以建造5座碉堡 。图1(b)给出了一种可行的建造方案 ,当然还有其他几种建造方案。
你的任务是编写一个程序,在给定地图描述的情况下 ,计算可以在城市中满足要求建造的碉堡的最大数量 。
输入
输入包括多组测试用例 。每组测试用例以包含正整数n的行开始 ,n是城市的大小,n最多为4。接下来的n行字符串分别描述地图的一行 ,其中字符“. ”表示开放空间 ,大写字母“X ”表示墙 。输入字符串中没有空格 。n=0 ,表示输入结束 。
输出
对于每个测试用例 ,输出一行 ,其中包含可以在城市中满足要求建造的碉堡的最大数量 。
输入样例
4
.X..
....
XX..
....
2
XX
.X
3
.X.
X.X
.X.
4
....
....
....
....
0
输出样例
5
1
5
4
(1)编程思路 。
由于题目中n不大于4 ,地图中最多16个位置 。因此 ,可以采用二进制枚举的方法 ,枚举在这n*n个位置中任选若干个位置建造碉堡的各种组合情况 ,然后对每个组合情况 ,逐个判断该组合情况中所建造的每个碉堡的可行性 。
(2)源程序 。
将上面的源程序提交给HDU题库HDU 1045 Fire Net (http://acm.hdu.edu.cn/showproblem.php?pid=1045) ,可以Accepted 。
【例2】子图像
问题描述
如果可以从图像B中删除一些行和一些列的像素 ,生成的图像与图像A相同,则称图像A是图像B的子图像 。图2所示的图像A是图像B的子图像 ,因为从图像B中移除中间一行和中间一列的像素后 ,所产生的图像与A相同 。
给定两个黑白图像A和B,确定A是否是B的子图像 。
输入
输入第一行包含两个整数r和c(1≤ r 、c≤ 20) ,表示图像A的行数和列数。以下r行 ,每行包含一个长度为c的字符串 ,给出一个r×c的0-1矩阵 ,表示图像A的像素 。下一行包含两个整数R和C(r≤ R≤ 20 ,c≤ C≤ 20) ,表示图像B的行数和列数 。以下R行 ,每行包含一个长度为C的字符串 ,给出一个代表图像B像素的R×C的0-1矩阵。0表示白色像素;1表示黑色像素 。
输出
如果图像A是图像B的子图像 ,则输出“Yes ”;否则 ,输出“No ” 。
输入样例
2 2
11
10
3 3
101
000
100
输出样例
Yes
(1)编程思路 。
可以通过在图像B对应的0-1矩阵中寻找是否存在图像A所对应的0-1矩阵来判断图像A是否是图像B的子图像 。
具体做法是:用二进制枚举矩阵B中R行的组合 ,若枚举的二进制数中1的个数正好为矩阵a的行数r ,则表示可以在矩阵B的R行中选出矩阵A的r行 。这种情况下,再用循环穷举的方法 ,看矩阵B的C列中 ,是否可以选出c列,矩阵B选中的r行在这c列上的值与矩阵A的值一致 。
(2)源程序 。
将上面的源程序提交给北大POJ题库POJ 3600 Subimage Recognition (http://poj.org/problem?id=3600) ,可以Accepted 。
【例3】查找0-1矩阵
问题描述
给定一个M×N的0-1矩阵 ,你能找到一些让每个列包含且仅包含一个1的行吗 。
输入
输入包括多组测试用例 。每组测试用例的第一行输入为M ,N(M≤ 16 ,N≤ 300) ,接下来的M行每行包含N个用空格分隔的整数0或1 。
输出
对于每个测试用例 ,如果你能找到它,输出“Yes, I found it ” ,否则输出“It is impossible ” 。
输入样例
3 3
0 1 0
0 0 1
1 0 0
4 4
0 0 0 1
1 0 0 0
1 1 0 1
0 1 0 0
输出样例
Yes, I found it
It is impossible
(1)编程思路。
本题同样采用二进制枚举各行的组合 ,再用位运算来判断所选的那些行是否满足每列只有一个1 。
由于题目中给出最多16行,因此可以用一个int型整数(32位>16)的每个二进制位来表示每列状态 。以输入样例中的4×4矩阵来说明。第0列4行上的数字分别为0 、1 、1 、0 ,对应二进制数为110 ,将其对应的十进制整数6保存到数组元素col[0]中 ,第1列4行上的数字分别为0 、0 、1 、1 ,对应二进制数为1100 ,将其对应的十进制整数12保存到数组元素col[1]中;同理 ,col[2]=0 ,col[3]=5 。
同样 ,对应输入样例中的3×3矩阵 ,则有 col[0]=4 ,col[1]=1 ,col[2]=2 。
当二进制枚举到状态i时 ,要判断所选行中,第j列是否有且只有1个1 。可以令t = col[j]&i ,这样就把枚举的行里面的1取了出来 。因为在枚举的二进制状态i中 ,选中的行相应位为1,未选中的行相应位为0 ,而 0 & 1=0 ,这样某列在未选中行上的1均会变成0 。
得到t值后 ,如果t=0 ,说明枚举的这些行对应的某列里面一个1都不含 ,肯定不满足要求 。如果 t != 0 ,再看 t&(t-1)的值 ,若该值等于0 ,表示 t 只有一个1 ,也就是在所选行中 ,第j列有且只有1个1;否则 ,t中不止1个1 ,不满足要求 。
(2)源程序 。
将上面的源程序提交给北大POJ题库POJ 3740 Easy Finding(http://poj.org/problem?id=3740),可以Accepted 。
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!