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

Cookie Monster问题:求数组元素全归零的最少移动次数

问题规则

  • 初始状态:桌上摆放若干堆饼干,每堆数量为正整数
  • 操作规则:每一步选择一个当前存在的堆的大小值p,对所有饼干数≥p的堆移除p块饼干,小于p的堆保持不变
  • 目标:计算吃完所有饼干需要的最少操作次数,同时输出对应的最优操作序列

给定测试用例基准

所有正确实现需要通过以下测试用例,返回匹配的预期步数:

  • 用例1:输入[1,2,3,4,5,6],预期最少步数3,最优序列[4,2,1]
  • 用例2:输入[2,3,5,8,13,21,34,55,89],预期最少步数5,最优序列[55,21,8,3,2]
  • 用例3:输入[1,10,17,34,43,46],预期最少步数5,最优序列[34,9,8,3,1]
  • 用例4:输入[11,26,37,44,49,52,68,75,87,102],预期最少步数6,最优序列[37,31,15,12,7,4]
  • 用例5:输入[2**n for n in range(10)](即1、2、4…512的2的幂序列),预期最少步数10,最优序列[512,256,128,64,32,16,8,4,2,1]

原有代码问题

之前写的相邻差贪心逻辑存在本质缺陷:最优操作选择的p值不一定是当前相邻堆的差值,比如用例3最优序列里的9、8,用例4里的31、15等值都不是初始堆的相邻差,贪心局部最优无法得到全局最短序列。
原有错误代码如下:

piles=[11, 26, 37, 44, 49, 52, 68, 75,87, 102]
p=piles
n=len(piles)
moves=0
while sum(piles)>0:
    for i in range(len(piles)-1,0,-1):
        if piles[i-1]<piles[i]:
            piles[i]=piles[i]-piles[i-1]
            if piles[i] in p:
                piles.remove(piles[i])
                moves+=1

正确求解思路

采用带记忆化的递归搜索+剪枝实现,核心逻辑和优化点如下:

  1. 状态压缩:每次操作后对堆数组做去重、删除0值、升序排序处理,相同大小的堆操作效果完全一致,0值是已吃完的堆,处理后能大幅降低状态空间
  2. 记忆化缓存:将处理后的排序元组作为缓存键,避免重复计算相同子问题的结果
  3. 递归边界:当状态为空(所有堆都吃完),返回0步和空操作序列
  4. 剪枝优化:
    • 合法p的取值范围只需要覆盖1到当前状态的最大堆值,超过最大值的p没有任何操作效果
    • 如果当前搜索到的最优步数已经等于当前状态的不同堆数量,直接终止搜索——理论上不同大小的堆最少需要对应数量的步数才能吃完,不可能得到更优解

可运行实现代码

from functools import lru_cache

def cookie_monster_solver(piles):
    # 初始状态预处理:去重、移除0、排序转元组适配缓存要求
    init_state = tuple(sorted(set(x for x in piles if x > 0)))

    @lru_cache(maxsize=None)
    def dp(state):
        # 递归边界:无剩余饼干
        if not state:
            return (0, [])
        max_val = state[-1]
        min_step = float('inf')
        best_seq = []
        # 遍历所有可能的合法操作p
        for p in range(1, max_val + 1):
            # 生成执行p操作后的新状态
            new_state = []
            for num in state:
                remain = num - p if num >= p else num
                if remain > 0:
                    new_state.append(remain)
            new_state = tuple(sorted(set(new_state)))
            # 递归求解子问题
            sub_step, sub_seq = dp(new_state)
            total_step = sub_step + 1
            # 更新最优解
            if total_step < min_step:
                min_step = total_step
                best_seq = [p] + sub_seq
                # 剪枝:达到理论下界直接终止
                if min_step == len(state):
                    break
        return (min_step, best_seq)
    
    return dp(init_state)

# 全测试用例验证
if __name__ == "__main__":
    test_cases = [
        [1,2,3,4,5,6],
        [2,3,5,8,13,21,34,55,89],
        [1,10,17,34,43,46],
        [11,26,37,44,49,52,68,75,87,102],
        [2**n for n in range(10)]
    ]
    for idx, case in enumerate(test_cases, 1):
        steps, seq = cookie_monster_solver(case)
        print(f"测试用例{idx}:最少操作次数{steps},最优序列{seq}")

运行上述代码可以全部匹配给定测试用例的预期结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:09:11