集覆盖问题的扩展版本

我一般不会问关于 SO 的问题,所以如果这个问题似乎不适合 SO,请告诉我(当然,仍然会感谢帮助)。

我还是一名学生,目前正在学习算法课程。我们最近了解了分支定界范式,由于我没有完全理解它,我尝试在我们的课本中做一些练习。我遇到了一个特殊的场景覆盖问题的特殊实例:

让 U 是一组元素,S = {S1,S2,...,sn} 是 U 的一组子集,其中所有集合 Si 的并集等于 U。将分支定界算法概述为找到 S 的最小子集 Q,因此对于 U 中的所有元素 u,Q 中至少有两个包含 u 的集合。具体来说,详细说明如何将问题分解为子问题以及如何计算上下界。

我的第一个想法是按降序对 S 中的所有集合 Si 进行排序,根据它们包含多少元素,这些元素尚未被当前选择的 S 子集覆盖至少两次,因此我们当前的 Q 实例。然后我想递归地解决这个问题,我按排序顺序选择第一个集合 Si 并进行一次递归调用,在那里我使用这个集合 Si 和一个我没有的地方(意思是从这些递归调用开始,子集是没有更长时间考虑)。如果我选择它,我将遍历这个所选子集 Si 中的每个元素并为其所有元素增加一个计数器(在递归调用之前),这样我最终会知道,当一个元素已经被两个或更多选择的元素覆盖时子集。由于我为每个递归调用对未选择的集合 Si 进行了排序,因此理论上(至少在我看来)我总是会做出目前最好的选择。而且由于我基本上创建了递归调用的二叉树,因为我总是使用当前选择的最佳子集进行一次调用,而我最终会覆盖所有 2^n 种可能性,这意味着最终我会找到最佳的解决方案。

我现在的问题是我不知道或者更不明白我将如何实现上限和下限的启发式算法,因此算法可以丢弃二叉树中的一些路径,这永远不会比当前最好的更好问:如果我能得到任何帮助,我将不胜感激。

biao12319880808 回答:集覆盖问题的扩展版本

这是一个简单的下限启发式方法:找到包含最大数量的尚未两次覆盖的元素的集合。 (如果有多个集合具有相同的、最大可能数量的这些元素,那么您选择哪个集合并不重要。)假设总共有 u 个这些元素,并且这个集合包含 k

这个下界也适用于常规集合覆盖问题。与分支定界一样,与简单地使用总是返回 0 的“启发式”相比,在给定实例上使用它可能会也可能不会导致更好的整体性能。

,

首先,一些建议:不要在每次递归/循环时重新排序 S。排序是一项代价高昂的操作 (O(N log N)),因此将其放入循环或递归中的成本通常高于从中获得的收益。通常,您希望在开始时排序一次,然后在整个算法中利用该排序。

您选择的排序,按 S 子集的长度降序是一个很好的“贪婪”排序,所以我会说只是提前做,之后不要重新排序。您无法跳过递归中不理想的子集,但检查冗余/非理想子集仍然比每次都重新排序要快。

现在你可以使用什么上限/下限?一般来说,您希望边界和边界检查尽可能简单有效,因为您将要大量检查它们。

考虑到这一点,上界很容易:使用您目前找到的最短集长度解决方案。最初将您的上限设置为 var bestQlength = int.MaxVal,某个最大值大于 n,即 S 中的子集数。然后在每次递归时检查是否 currentQ.length > bestQlength,如果是,那么这个分支超过上限,你“修剪”它。显然,当您找到新的解决方案时,您还需要检查它是否比当前的 bestQ 更好(更短),如果是,则同时更新 bestQbestQlength

一个好的下限有点棘手,我能想到的最简单的这个问题是:在你添加一个新的子集 Si 到你的 currentQ 之前,检查一下 {{1} } 有 any 元素尚未出现在 Si 两次或更多次,如果没有,则此 currentQ 不能以任何方式对 Si您正在尝试构建的解决方案,因此只需跳过它并转到 S 中的下一个子集。

本文链接:https://www.f2er.com/264731.html

大家都在问