题目来源:
HihoCoder1317
题目描述:
在N行 M列的棋盘中放置一定数目的棋子,要求从其中选出若干行,使得每一列中恰好有一枚棋子。HihoCoder1317
题目描述:
例如,对于下面的棋局,选择1、3、4行,则符合要求:
解答:
·精确覆盖问题:
以上问题可以总结为“精确覆盖问题”。具体定义如下:
给定一个集合S和它的n个子集s1, s2, ... sn。要求从中选择k个子集满足:
① ∪si = S
② 对于任意的i≠j, si∩sj = ∅。
对于本题目,S即为m列,每一行的棋子摆放局面都是S的一个子集。
·解法:
对于精确覆盖问题,最直观的解法就是枚举S的所有子集和所有的子集选择方案,寻找符合条件的方案。但是对于有x个元素的集合,子集数目为2^x个,因而选择的子集的策略就有2^(2^x)种,这是一个非常庞大的数字。算法执行效率非常低。
精确覆盖问题比较好的解法是利用一种称为“跳舞链”的数据结构进行搜索。方法如下:
·数据结构:
首先定义数据的存储结构,对于精确覆盖问题,一定可以构造一个二维的数表,其中数表的每一行代表一个子集,而每一列则代表全集中的一个元素。对于数表中第i行第j列的元素, 如果第i个子集中包含了全集中的第j个元素,则值为1,否则,值为0。上面例子中的棋局可以用下面的矩阵来表示:
给定一个集合S和它的n个子集s1, s2, ... sn。要求从中选择k个子集满足:
① ∪si = S
② 对于任意的i≠j, si∩sj = ∅。
对于本题目,S即为m列,每一行的棋子摆放局面都是S的一个子集。
·解法:
对于精确覆盖问题,最直观的解法就是枚举S的所有子集和所有的子集选择方案,寻找符合条件的方案。但是对于有x个元素的集合,子集数目为2^x个,因而选择的子集的策略就有2^(2^x)种,这是一个非常庞大的数字。算法执行效率非常低。
精确覆盖问题比较好的解法是利用一种称为“跳舞链”的数据结构进行搜索。方法如下:
·数据结构:
首先定义数据的存储结构,对于精确覆盖问题,一定可以构造一个二维的数表,其中数表的每一行代表一个子集,而每一列则代表全集中的一个元素。对于数表中第i行第j列的元素, 如果第i个子集中包含了全集中的第j个元素,则值为1,否则,值为0。上面例子中的棋局可以用下面的矩阵来表示:
0 1 0 1
1 0 1 0
1 0 0 0
0 0 1 1
1 0 1 0
1 0 0 0
0 0 1 1
此时,整个问题就转换为一个稀疏矩阵,这里我们利用双向十字链表存储该矩阵,如下