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

从集合的集合中获取指定组合的方法及计数问题

优化解法:从多集合选元素组成指定组合的计数问题

问题明确

给定n个集合 ( S_1, S_2, ..., S_n ),以及大小为n的目标集合 ( T ),需要:

  1. 判断是否能从每个集合选一个元素,使得选出的元素恰好构成T(无重复、全覆盖);
  2. 若可行,计算所有符合条件的选择方式数量。

暴力枚举的时间复杂度是各集合大小的乘积,当n或集合规模较大时完全不可行,以下是几种高效优化方案:


方案1:回溯剪枝

通过提前排除已选元素的分支,大幅减少无效遍历:

  • 维护已选元素集合和当前处理的集合索引;
  • 遍历当前集合的元素时,仅保留「属于T且未被选过」的元素,递归处理下一个集合;
  • 递归到最后一个集合时,若已选元素正好是T,计数加1;
  • 回溯时移除当前元素,继续尝试其他可能。

代码示例(Python)

def count_valid_selections(sets, target):
    target_set = set(target)
    n = len(sets)
    count = 0

    def backtrack(index, selected):
        nonlocal count
        if index == n:
            if selected == target_set:
                count += 1
            return
        for num in sets[index]:
            if num in target_set and num not in selected:
                selected.add(num)
                backtrack(index + 1, selected)
                selected.remove(num)

    backtrack(0, set())
    return count if count > 0 else None  # 返回数量,None表示不可行

适用场景:n≤15,目标元素无重复,剪枝效率极高。


方案2:状态压缩动态规划

用二进制掩码表示已选元素的状态,适合n≤20的场景:

  1. 先将目标T中的元素映射为0~n-1的位索引;
  2. 定义dp[mask]表示已选元素对应掩码为mask时的方案数;
  3. 初始状态dp[0] = 1(未选任何元素时1种方案);
  4. 遍历每个集合,对每个现有状态,若集合中的元素未被选过,则更新新状态的方案数;
  5. 最终结果为dp[full_mask](full_mask是所有位为1的掩码),若为0则不可行。

代码示例(Python)

def count_valid_selections_dp(sets, target):
    target_map = {num: idx for idx, num in enumerate(target)}
    n = len(sets)
    full_mask = (1 << n) - 1
    dp = [0] * (1 << n)
    dp[0] = 1

    for s in sets:
        new_dp = dp.copy()
        for mask in range(full_mask, -1, -1):
            if dp[mask] == 0:
                continue
            for num in s:
                if num not in target_map:
                    continue
                bit = target_map[num]
                if not (mask & (1 << bit)):
                    new_dp[mask | (1 << bit)] += dp[mask]
        dp = new_dp

    result = dp[full_mask]
    return result if result > 0 else None

时间复杂度:( O(n * 2^n * k) ),k为集合平均大小,n≤20时计算量可控。


方案3:二分图完美匹配计数

将问题转化为二分图的完美匹配计数:

  • 左节点:n个集合;
  • 右节点:T中的n个元素;
  • 若集合i包含元素t,则左节点i与右节点t连边;
  • 求该二分图的完美匹配数量,存在匹配则可行,数量即为方案数。

实现思路

可以用高斯消元计算矩阵行列式的方法(将邻接矩阵转为模质数的矩阵,行列式的值即为完美匹配数),时间复杂度( O(n^3) ),适合n≤100的场景。


解法对比

解法适用场景时间复杂度范围
暴力枚举n≤5,集合元素极少( O(k_1k_2...*k_n) )
回溯剪枝n≤15,目标元素无重复远低于暴力枚举,依赖剪枝效率
状态压缩DPn≤20( O(n2^nk) )
二分图计数n≤100( O(n^3) )(高斯消元)

示例验证

以题目中的输入为例:

  • 集合列表:[[1,2,3,7], [1,2,4,5], [1,3,5,6], [4,5,6]]
  • 目标集合:{1,2,3,4}

通过回溯或DP计算,最终得到可行方案共3种:

  1. 集合1选1,集合2选2,集合3选3,集合4选4
  2. 集合1选2,集合2选1,集合3选3,集合4选4
  3. 集合1选3,集合2选2,集合3选1,集合4选4

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:58:01