You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从n choose k组合中找出覆盖所有n choose q组合的最小子集

问题与解决方案

问题描述

给定人员列表 people = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6', 'P7'],通过itertools.combinations生成:

  • allComb4:所有4人组合(即C(7,4))
  • allComb2:所有2人组合(即C(7,2))

需要从allComb4中筛选出数量最少的元素集合,使得allComb2中的任意2人对,都能在所选的某个4人组合中找到(即该2人对是这个4人组合的子集)。已知条件q < k(这里q=2,k=4)。期望输出示例为:

[['P1', 'P2', 'P5', 'P6'], ['P1', 'P3', 'P4', 'P7'], ['P2', 'P3', 'P5', 'P7'], ['P2', 'P4', 'P5', 'P6'], ['P3', 'P4', 'P6', 'P7']]

解决方案

这个问题本质是集合覆盖问题(Set Cover Problem),属于NP难问题。对于小规模数据(比如这里n=7),可以通过暴力搜索找到最优解;数据量较大时,可使用贪心算法快速得到近似最优解。

方法1:暴力搜索(精确最优解)

从最小的候选集合数量开始尝试,逐一检查是否存在符合条件的子集,找到第一个满足条件的集合即为最小数量的解。

import itertools

# 初始化人员列表与所有组合
people = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6', 'P7']
allComb4 = list(itertools.combinations(people, 4))
allComb2 = set(itertools.combinations(people, 2))  # 用集合加速判断

def is_complete_cover(selected_groups):
    """检查选中的4人组合是否覆盖所有2人对"""
    covered_pairs = set()
    for group in selected_groups:
        # 生成当前4人组的所有2人对,加入覆盖集合
        covered_pairs.update(itertools.combinations(group, 2))
    return covered_pairs == allComb2

# 从1个4人组开始,逐步增加数量,直到找到符合条件的解
for candidate_count in range(1, len(allComb4) + 1):
    # 遍历所有candidate_count个4人组的组合
    for candidate in itertools.combinations(allComb4, candidate_count):
        if is_complete_cover(candidate):
            # 转换为列表格式输出
            result = [list(group) for group in candidate]
            print(result)
            exit()  # 找到第一个解即退出,保证是最小数量

方法2:贪心算法(快速近似解)

每次选择能覆盖最多未被覆盖2人对的4人组合,直到所有2人对都被覆盖。该方法速度更快,适合大规模数据,对于小规模数据也可能得到最优解。

import itertools

people = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6', 'P7']
allComb4 = list(itertools.combinations(people, 4))
allComb2 = set(itertools.combinations(people, 2))

remaining_pairs = allComb2.copy()
selected_groups = []

while remaining_pairs:
    best_group = None
    max_new_covered = 0
    # 找到当前能覆盖最多剩余2人对的4人组
    for group in allComb4:
        group_pairs = set(itertools.combinations(group, 2))
        # 计算该组能覆盖的未覆盖2人对数量
        new_covered = len(group_pairs & remaining_pairs)
        if new_covered > max_new_covered:
            max_new_covered = new_covered
            best_group = group
    # 记录选中的组,并移除已覆盖的2人对
    selected_groups.append(list(best_group))
    remaining_pairs -= set(itertools.combinations(best_group, 2))

print(selected_groups)

说明

  • 暴力搜索会遍历所有可能的组合,确保找到最优解,但当allComb4数量较大时,计算量会急剧增加。
  • 贪心算法的时间复杂度更低,虽然理论上不能保证一定得到最优解,但在实际场景中往往能得到接近最优的结果,且执行速度远快于暴力搜索。

内容的提问来源于stack exchange,提问作者Ciprian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:31:32