给定一个包含 $n$ 个元素的集合 $U$,以及 $U$ 的子集集合 $S = \{S1, S2…,Sm\}$,其中每个子集 $Si$ 都有相关的成本。我们的目标是找到一个成本最小的 $S$ 的子集合,使其覆盖 $U$ 中的所有元素。
示例:
U = {1,2,3,4,5}
S = {S1,S2,S3}
S1 = {4,1,3}, Cost(S1) = 5
S2 = {2,5}, Cost(S2) = 10
S3 = {1,4,3,2}, Cost(S3) = 3
Output: Minimum cost of set cover is 13 and
set cover is {S2, S3}
There are two possible set covers {S1, S2} with cost 15
and {S2, S3} with cost 13.
为什么它有用?
它是 Karp 提出的 NP 完全问题之一,这一特性在 1972 年被证实。其他应用场景包括:边覆盖、顶点覆盖。
一个有趣的例子是 IBM 发现计算机病毒的过程(来源:维基百科):
- 元素:5000 种已知病毒。
- 集合:9000 个子串,这些子串由病毒中 20 个或更多连续字节组成,且未出现在‘良性’代码中。
最终找到了一个大小为 180 的集合覆盖。这意味着,为了验证已知计算机病毒的存在,我们只需要搜索这 180 个子串就足够了。
另一个例子:
设想通用汽车需要购买一定数量的各种物资,且供应商针对不同的材料组合提供各种优惠方案(例如:供应商 A 提供 2 吨钢 + 500 块瓷砖,价格 $x;供应商 B 提供 1 吨钢 + 2000 块瓷砖,价格 $y;等等)。我们可以使用集合覆盖来找到获取所有材料同时最小化成本的最佳方式。
集合覆盖是 NP-Hard 问题:
由于集合覆盖是一个已知的 NP-Hard 问题,目前没有多项式时间的精确解法。但是,存在一种多项式时间的贪心近似算法,该贪心算法提供了 $\ln n$ 的近似比。
2-近似贪心算法:
设 $U$ 为元素的全集,$\{S1, S2, … Sm\}$ 为 $U$ 的子集集合,$Cost(S1), C(S2), … Cost(Sm)$ 为各子集的成本。
1) 令 I 表示目前已被覆盖的元素集合。初始化 I = {}
2) 当 I 不等于 U 时,执行以下操作:
a) 在 {S1, S2, ... Sm} 中找到性价比(Cost Effectiveness)最小的集合 Si,
即:成本 C(Si) 与新增元素数量的比值最小。
基本上,我们要选择使以下数值最小的集合:
Cost(Si) / |Si - I|
b) 将选定的 Si 中的元素添加到 I 中,即 I = I U Si
示例: 让我们利用上面的示例来理解贪心算法。
第一次迭代:
$I = \{\}$
对于 $S1$,每个新元素的成本 = $Cost(S1)/
= 5/3$
对于 $S2$,每个新元素的成本 = $Cost(S2)/
= 10/2$
对于 $S3$,每个新元素的成本 = $Cost(S3)/
= 3/4$
因为 $S3$ 的数值最小,所以选择 $S3$,此时 $I$ 变为 $\{1,4,3,2\}$。
第二次迭代:
$I = \{1,4,3,2\}$
对于 $S1$,每个新元素的成本 = $Cost(S1)/
= 5/0$ (注意:$S1$ 没有向 $I$ 中添加任何新元素)。
对于 $S2$,每个新元素的成本 = $Cost(S2)/
= 10/1$ (注意:$S2$ 仅向 $I$ 中添加了元素 5)。
对于上述示例,贪心算法提供了最优解,但它并不总是能提供最优解。
让我们考虑下面这个例子。
S1 = {1, 2}
S2 = {2, 3, 4, 5}
S3 = {6, 7, 8, 9, 10, 11, 12, 13}
S4 = {1, 3, 5, 7, 9, 11, 13}
S5 = {2, 4, 6, 8, 10, 12, 13}
Let the cost of every set be same.
The greedy algorithm produces result as {S3, S2, S1}
The optimal solution is {S4, S5}
证明上述贪心算法是 Logn 近似的。
设 $OPT$ 为最优解的成本。假设在上述贪心算法的某次迭代之前已经覆盖了 $k-1$ 个元素。那么第 $k$ 个元素的成本 $\le OPT / (n-k+1)$ (注意:元素的成本是通过其所在集合的成本除以该集合新增的元素数量来评估的)。
我们是如何得出这个结果的呢?因为第 $k$ 个元素尚未被覆盖,所以存在一个集合 $Si$,它在贪心算法的当前步骤之前未被覆盖,并且它存在于 $OPT$ 中。由于贪心算法总是选择性价比最高的 $Si$,因此被选集合中的单元素成本必然小于 $OPT$ 除以剩余元素数量的值。
因此,第 $k$ 个元素的成本 $\le OPT/
$ (注意:$U-I$ 是贪心算法中尚未被覆盖的元素集合)。
$
$ 的值为 $n – (k-1)$,即 $n-k+1$。
贪心算法的成本 = n 个元素的成本之和
[在上述公式中令 k = 1, 2..n]
<= (OPT/n + OPT/(n-1) + ... + OPT/n)
<= OPT(1 + 1/2 + ...... 1/n)
[因为 1 + 1/2 + .. 1/n 约等于 Log n]
<= OPT * Logn
集合覆盖问题是一个经典的 NP-hard 问题,其目标是找到能够覆盖给定全集中所有元素的最少数量的集合。换句话说,给定一个全集 $U$ 和 $U$ 的子集集合 $S$,集合覆盖问题就是要在 $S$ 中找到一个子集 $C$,使得 $U$ 中的每一个元素都至少包含在 $C$ 的一个集合中。