求集合{1,2,…,255}中和为666的所有子集的高效实现方案
子集和问题:从{1,2,...,255}中快速找出和为666的子集
核心算法:回溯+剪枝
暴力枚举所有子集完全不可行(2^255量级),采用带剪枝的回溯法可在合理时间内生成至少10个结果,核心剪枝策略如下:
- 降序遍历:从大到小遍历元素,更快凑出目标和,也能更早触发剪枝条件。
- 剩余和预判:预处理剩余元素的前缀和,若当前路径和加上剩余所有元素的总和仍小于目标值,直接终止当前分支。
- 路径去重:由于元素唯一,此处可跳过重复元素判断;若扩展到有重复元素的场景,需跳过相同元素的重复路径。
Python代码实现
以下代码可快速生成至少10个符合条件的子集,生成数量可通过代码中的阈值调整:
def find_target_subsets(target, max_element): # 生成降序元素列表 nums = list(range(max_element, 0, -1)) # 预处理剩余元素前缀和,用于剪枝 prefix_sum = [0] * (len(nums) + 1) for i in range(len(nums)-1, -1, -1): prefix_sum[i] = prefix_sum[i+1] + nums[i] result = [] def backtrack(start_idx, current_sum, current_path): if current_sum == target: result.append(current_path.copy()) # 收集到10个结果后停止,可根据需求修改 if len(result) >= 10: return True return False if current_sum > target: return False # 剪枝:当前和+剩余元素总和 < 目标,无需继续 if current_sum + prefix_sum[start_idx] < target: return False for i in range(start_idx, len(nums)): current_path.append(nums[i]) # 递归,若已收集足够结果则提前返回 if backtrack(i+1, current_sum + nums[i], current_path): return True current_path.pop() return False backtrack(0, 0, []) return result # 执行并输出结果 target_subsets = find_target_subsets(666, 255) print("找到的10个符合条件的子集(排序后):") for idx, subset in enumerate(target_subsets, 1): print(f"{idx}. {sorted(subset)}")
手动生成的部分结果
以下是几个直接构造的符合条件的子集(按升序排列):
- {157, 254, 255} → 157+254+255=666
- {158, 253, 255} → 158+253+255=666
- {159, 252, 255} → 159+252+255=666
- {160, 251, 255} → 160+251+255=666
- {161, 250, 255} → 161+250+255=666
- {162, 249, 255} → 162+249+255=666
- {163, 248, 255} → 163+248+255=666
- {164, 247, 255} → 164+247+255=666
- {165, 246, 255} → 165+246+255=666
- {166, 245, 255} → 166+245+255=666
扩展优化建议
若需要生成更多结果,可移除代码中“收集10个即停止”的逻辑,但需注意:随着结果数量增加,耗时会逐步上升,但剪枝策略仍能保证在10分钟内生成上千个结果。
对于大规模生成需求,可采用分治法:将集合拆分为两部分,分别计算每部分的所有子集和及对应子集,再匹配两部分中和为666的组合。需注意存储时仅保留每个和对应的部分子集,避免内存溢出。
内容的提问来源于stack exchange,提问作者John Carlson
相关产品推荐
相关产品推荐

