Last Updated: 2024-04-27 03:25:43 Saturday
-- TOC --
算法如诗...烧脑又性感...
限制输入全部为positive integer,每个元素只能使用一次,判定性问题,即返回True或False。
* Recurrence:
SS(list,target) = SS(list[1:],target-list[0]) | SS(list[1:],target)
* Base case:
SS(list,0) = True
def subset_sum_dp(lst, target) -> bool:
assert len(lst) != 0
rec = [0] * (target+1)
rec[0] = 1
for v in lst:
for t in reversed(range(v,target+1)):
rec[t] |= rec[t-v]
if rec[-1] != 0:
return True
return False
计算满足条件的组合数,返回int。
* Recurrence:
SS(list,target) = SS(list[1:],target-list[0]) + SS(list[1:],target)
* Base case:
SS(list,0) = 1
def subset_sum_num_dp(lst, target) -> int:
rec = [0] * (target+1)
rec[0] = 1
for v in lst:
for t in reversed(range(v,target+1)):
rec[t] += rec[t-v]
return rec[-1]
复杂度:\(O(n\cdot T)\)
输入全部都是positive integer,但每个coin数量无限,判定性问题,返回True或False。
* Recurrence:
MC(coins,amount) = MC(coins,amount-coins[0]) | MC(coins[1:],amount)
* Base case:
MC(coins,0) = True
def make_change_dp(coins, amount) -> bool:
assert len(coints) != 0
rec = [0] * (amount+1)
rec[0] = 1
for c in coins:
for i in range(c, amount+1):
rec[i] |= rec[i-c]
if rec[-1] != 0:
return True
return False
计算满足条件的组合数:
* Recurrence:
MC(coins,amount) = MC(coins,amount-coins[0]) + MC(coins[1:],amount)
* Base case:
MC(coins,0) = 1
def make_change_num_dp(coins, amount) -> int:
rec = [0] * (amount+1)
rec[0] = 1
for c in coins:
for i in range(c, amount+1):
rec[i] += rec[i-c]
return rec[-1]
复杂度:\(O(c\cdot A)\)
元素只能使用一次的01问题,从高到低计算,而元素无限多或可多次使用的所谓Complete问题,从低到高计算。
def knapsack_dp(W, P, T) -> int:
assert len(W) == len(P)
rec = [0] * (T+1)
for i,w in enumerate(W):
for t in reversed(range(w,T+1)):
rec[t] = max(rec[t], rec[t-w]+P[i])
return rec[-1]
01-Knapsack问题不能使用Greedy算法的证明
举出一个反例:
有三件物品,重量分别为10,6,1,价值分别为24,20,1,包大小为12。
使用Greedy,结果为:24+1+1=26
最优解为:20+20=40
def knapsack_complete_dp(W, P, T) -> int:
assert len(W) == len(P)
rec = [0] * (T+1)
for i,w in enumerate(W):
for t in range(w, T+1):
rec[t] = max(rec[t], rec[t-w]+P[i])
return rec[-1]
本文链接:https://cs.pynote.net/ag/dp/202403266/
-- EOF --
-- MORE --