例如,我得到了一组列表:
[[0, 1, 3], [0, 2, 12], [6, 9, 10], [2, 4, 11], [2, 7, 13], [3, 5, 11], [3, 7, 10], [4, 10, 14], [5, 13, 14]]
我需要找到此列表包含的不相交子集的最大数量。在这种情况下,答案是4
。
另一个例子是列表:
[[0, 1, 12], [0, 4, 11], [0, 7, 19], [0, 15, 17], [0, 16, 18], [1, 4, 16], [1, 13, 25], [2, 4, 23], [2, 10, 27], [2, 12, 19], [2, 14, 22], [2, 16, 20], [3, 6, 13], [3, 7, 22], [3, 10, 14], [3, 20, 26], [4, 7, 13], [4, 17, 22], [5, 7, 25], [5, 9, 22], [5, 10, 21], [5, 11, 23], [5, 12, 20], [5, 13, 16], [5, 14, 15], [6, 7, 17], [6, 10, 23], [7, 11, 20], [7, 14, 27], [7, 18, 23], [8, 12, 26], [8, 14, 17], [8, 22, 23], [11, 12, 18], [12, 17, 21], [12, 23, 25], [13, 19, 20], [13, 21, 24], [18, 20, 25], [18, 24, 26], [19, 24, 27]]
在这里,答案是8。
我知道这个问题很难解决,所以我想出了一种半蛮力的方法。
我首先通过将子集添加到不相交的子集列表中来获得近似答案。因此,每当遍历一个集合时,我都会检查它是否已存在于不相交的子集列表中。如果不是,我将其添加到列表中。这给了我一个大概的数字,它可能是也可能不是最大子集数。
def is_disjoint(disjoints, i, j, k):
disjoints_flat = list(chain.from_iterable(disjoints))
if (i in disjoints_flat) or (j in disjoints_flat) or (k in disjoints_flat):
return False
return True
.... other code
# disjoint determination
n_disjoints = 0
disjoints = []
# sets is the input
for set in sets:
if is_disjoint(disjoints, set[0], set[1], set[2]):
if is_dis:
n_disjoints += 1
disjoints.append(set)
获得棒球场之后,我反复检查更高的可能值。为此,我尝试从给定的一组值中生成所有可能的k
大小的子集(k
初始化为上面获得的数字),然后尝试检查是否可以找到一个子集那是不相交的。如果这样做,则检查k+1
大小的子集。但是,我的代码在生成k
可能的子集的同时运行速度非常慢。我希望有人可以提出任何加快解决方案的方法。这是蛮力搜索部分的代码。
def is_subset_disjoint(subset):
disjoints = []
n_disjoints = 0
for set in subset:
if is_disjoint(disjoints, set[0], set[1], set[2]):
disjoints.append(set)
n_disjoints += 1
if n_disjoints == len(subset):
return True
return False
..... other code
curr = n_disjoints+1
while n_disjoints <= n_sets:
all_possible_subsets = [list(i) for i in combinations(sets, curr)] # This runs really really slowly (makes sense since exponential for large values)
for subset in all_possible_subsets:
if is_subset_disjoint(subset):
n_disjoints += 1
curr += 1
continue
break
答案 0 :(得分:3)
创建一个图形,以使列表成为顶点,并且如果两个顶点不相交,则将其连接起来。比您的问题是找到maximum independent set。
在任何情况下,使用图结构都比使用子集和对其进行操作更简单,更快捷。
答案 1 :(得分:1)
如前所述,您应该将问题减少到找到最大独立集,这可以减少到最大集团问题。
我刚刚实现了相当快的算法,很高兴与您分享它,但是我没有足够的力量来解释它,因为它足够复杂和复杂。您可以浏览一下核心思想here。
随时使用以下代码:https://gist.github.com/mingaleg/e1872483d0d0618fe1acacccbf741050
在您作为示例提供的大列表上,它适用于6 sec
(如果使用的是0.5 sec
,则pypy
)。
答案 2 :(得分:0)
您可以将递归与生成器一起使用:
if(isset($_POST['submit']))
{
sleep(2)
$messagename = $_POST['messagename'];
$subject = $_POST['subject'];
header("Location: http://example.com/newsletters/create_newsletter.php?template=new&messagename=".$messagename."&subject=".$subject);
}
if(isset($_GET['template'])
{
$messagename = $_GET['messagename'];
$subject = $_GET['subject'];
echo "hello robert now you are working on the template";
}
?>
输出:
all_vals = [[0, 1, 3], [0, 2, 12], [6, 9, 10], [2, 4, 11], [2, 7, 13], [3, 5, 11], [3, 7, 10], [4, 10, 14], [5, 13, 14]]
class _subsets:
def is_disjoint(self, _vals:list) -> bool:
_c = [i for b in _vals for i in b]
return len(_c) == len(set(_c))
def _combos(self, _sets, _current = []):
if len(_current) == len(_sets) and self.is_disjoint(_current):
yield _current
else:
if len(_current) > 1 and self.is_disjoint(_current):
yield _current
for i in _sets:
if i not in _current:
yield from self._combos(_sets, _current+[i])
def __call__(self, _sets):
return max(list(self._combos(_sets)), key=len)
_result = _subsets()(all_vals)
print(f'{len(_result)}: {_result}')