知识库 · 文字讲解,AI 整理
子集和
给定整数 $a_1,\dots,a_n$ 和目标 $T$,问是否存在下标集合 $I$ 使
LaTeX
$$\sum_{i\in I}a_i=T.$$
选或不选
按下标 $i$ 和当前和 $s$ 递归,每一步跳过 $a_i$ 或者选上它:
LaTeX
$$F(i,s)=F(i+1,s)\lor F(i+1,s+a_i),\qquad F(n,s)=[s=T].$$
朴素枚举是 $2^n$ 种组合。同一个 $(i,s)$ 会被不同的路径反复走到,缓存起来就是 动态规划:
python8 行
from functools import lru_cache
def subset_sum(nums, target):
@lru_cache(None)
def solve(i, total):
if i == len(nums):
return total == target
return solve(i+1, total) or solve(i+1, total+nums[i])
return solve(0, 0)剪枝
所有数都非负时,当前和 $s>T$ 以后再选只会更大,可以剪掉。有负数时这个剪枝是错的:后面的数可能把和拉回来。
更一般的做法:算出剩下的数能凑出的最大和与最小和,目标不在 $[s+\min,\ s+\max]$ 里才剪。这是 回溯 里「剪枝要先证明」的例子。
用到它的地方
核对
这一条是文字讲解,由 AI 整理,没有可以数值核对的步骤;作者读过后才公开。