求1000+个桶的4元组合筛选方案:总重量<100kg
可行解决方案
1. 排序+剪枝+二分查找优化
先将所有桶的重量按从小到大排序,这是核心优化的基础。排序后可以通过剪枝和二分查找大幅减少无效组合的遍历:
- 提前终止无效分支:比如当选中前k个桶的总和,加上后续最小的(4-k)个桶的总和已≥100时,直接跳过当前分支,无需继续遍历。
- 用二分查找快速定位有效范围:对于已选的3个桶,计算剩余允许的最大重量(
100 - 三个桶的总和),通过二分查找找到数组中最后一个符合条件的桶的索引,一次性确定所有可搭配的第四个桶,避免逐个遍历。
示例代码:
import bisect # 假设weights是所有桶的重量列表 weights.sort() valid_combinations = [] n = len(weights) for i in range(n - 3): w1 = weights[i] # 前四个最小的组合已超标,后续更大的组合必然超标,直接终止循环 if w1 + weights[i+1] + weights[i+2] + weights[i+3] >= 100: break for j in range(i+1, n - 2): w12 = w1 + weights[j] if w12 + weights[j+1] + weights[j+2] >= 100: break for k in range(j+1, n - 1): w123 = w12 + weights[k] # 处理浮点数精度,避免等于100的情况被误判 max_allowed = 100 - w123 - 1e-9 # 找到第一个大于max_allowed的索引,减1就是最大有效索引 l_upper = bisect.bisect_left(weights, max_allowed, k+1) - 1 if l_upper > k: # 批量生成所有有效4元组 for l in range(k+1, l_upper + 1): valid_combinations.append((weights[i], weights[j], weights[k], weights[l])) # 若仅需统计数量,直接累加(l_upper - k)即可,无需生成每个组合
2. 重复重量的组合数优化
如果存在大量重量相同的桶,可先去重并记录每个重量对应的桶的数量,用组合数学公式计算有效组合数,避免生成重复组合:
- 比如有m个重量为w的桶,从中选k个的组合数为
math.comb(m, k) - 跨不同重量的组合,比如选2个w1和2个w2,组合数为
math.comb(m1,2)*math.comb(m2,2)
这种方式能将万亿级的枚举量直接压缩为数学计算,速度提升几个数量级。
3. 分块处理(超大数据量场景)
当桶的数量过万时,全量处理可能导致内存溢出,可将排序后的数组分块处理:
- 拆分数组为多个小模块,分别计算:
- 单模块内的4元组合
- 跨2个模块的组合(1+3、2+2、3+1)
- 跨3个模块的组合(1+1+2、1+2+1、2+1+1)
- 跨4个模块的组合(1+1+1+1)
- 每块处理完成后直接输出结果,再清理内存处理下一块,避免内存过载。
关键注意事项
- 浮点数精度:若重量为浮点数,判断总和时需预留微小误差(如
sum < 100 - 1e-9),避免因精度问题误判临界值。 - 优先级:优先用重复重量的组合数计算,其次是排序+剪枝+二分查找,最后考虑分块处理,根据数据规模选择最优方案。
内容的提问来源于stack exchange,提问作者vamshi krishna
相关产品推荐
相关产品推荐

