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

为何用combinations方法求解CCC17S3计数问题失败?

2017 CCC S3 解法问题排查

我针对2017年CCC竞赛S3题写了一份解法,代码如下:

from itertools import combinations

num_pieces = int(input())
pieces = input()
pieces_list = list(combinations([int(num) for num in pieces.split()], 2))
possible_heights = [0]*4000
for item in pieces_list:
    possible_heights[item[0]+item[1]-1] += 1

print(max(possible_heights), possible_heights.count(max(possible_heights)))

我的思路是遍历所有木板长度的两两组合,计算它们构成的高度并统计次数,列表索引对应木板高度,列表最大值为最多能搭建的同高度木板数量,其出现次数为符合条件的不同高度数。但我发现代码似乎未考虑到能延长木板长度的某些组合,希望帮忙排查问题。


代码核心错误分析

  1. 仅考虑双木板拼接支撑:完全忽略了单木板作为支撑的情况,这会遗漏大量最优解。比如有5块长度为2的木板,最优解是做5个高度为2的支撑,但你的代码只会统计两两拼接成高度4的支撑,最多输出2个,明显错误。
  2. 未考虑木板使用限制:combinations统计的是所有可能的双木板组合数,但每块木板只能用一次。比如三块长度2的木板,combinations会统计3次高度4的组合,但实际只能搭建1个高度4的支撑,剩下一块2还能做1个支撑,总支撑数是2,远大于你的代码输出的1。
  3. 未覆盖多木板拼接场景:完全没考虑三块及以上木板拼接成同一高度支撑的情况,导致部分合法组合被遗漏。

正确解法思路与代码

思路

  1. 统计木板频率:先统计每个长度的木板出现次数,方便后续计算。
  2. 枚举最大可能支撑数:从总木板数(最大可能值)向下枚举,直到找到第一个存在至少一个高度h,能搭建出该数量的同高度支撑。
  3. 验证高度合法性:对每个候选支撑数,检查是否存在高度h,使得现有木板能组合出k个和为h的支撑(每块木板仅用一次)。

代码实现

def main():
    import sys
    input = sys.stdin.read().split()
    n = int(input[0])
    lengths = list(map(int, input[1:n+1]))
    
    # 统计每个长度的木板数量,长度范围1~200
    freq = [0] * 201
    total_len = 0
    max_len = 0
    for l in lengths:
        freq[l] += 1
        total_len += l
        if l > max_len:
            max_len = l
    
    # 从最大可能的k开始枚举(总木板数)
    for k in range(n, 0, -1):
        # h的最小可能值是max_len(最长木板必须能作为支撑或被拼接)
        # h的最大可能值是total_len // k(总长度至少要够k个支撑)
        min_h = max_len
        max_h = total_len // k
        if min_h > max_h:
            continue
        
        count = 0
        # 检查每个可能的h
        for h in range(min_h, max_h + 1):
            used = 0
            valid = True
            # 复制频率数组避免修改原数据
            temp_freq = freq.copy()
            
            # 先处理长度等于h的木板,直接作为支撑
            used += temp_freq[h]
            temp_freq[h] = 0
            
            # 处理长度小于h的木板,从小到大处理避免重复计算
            for l in range(1, h):
                if temp_freq[l] == 0:
                    continue
                # 先处理和h-l的组合
                if h - l > l:
                    pairs = min(temp_freq[l], temp_freq[h - l])
                    used += pairs
                    temp_freq[l] -= pairs
                    temp_freq[h - l] -= pairs
                # 处理多个l拼接成h的情况(l * m = h)
                if h % l == 0:
                    m = h // l
                    num_supports = temp_freq[l] // m
                    used += num_supports
                    temp_freq[l] -= num_supports * m
            
            # 检查是否能达到k个支撑
            if used >= k:
                count += 1
        
        if count > 0:
            print(k, count)
            return
    
    # 最坏情况,只能做1个支撑(总长度)
    print(1, 1)

if __name__ == "__main__":
    main()

代码说明

  • 统计木板频率后,从最大可能的支撑数k开始枚举,一旦找到合法的k就直接输出,保证效率。
  • 对每个k,遍历可能的高度h,通过贪心算法验证是否能凑出k个和为h的支撑:优先用等长木板直接作为支撑,再用两两组合,最后用多块短木板拼接。
  • 当找到第一个合法的k时,统计对应的合法h数量并输出,即为最优解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 12:34:56