动态规划题目:
- 最少硬币问题 Make changes using the fewest coins:
- 0-1背包 0-1 package
- 最长回文子串 longest palindromic substring
- 最长公共子串 longest common subsequence
- 最长公共子序列 longest common substring
- 最长连续子串 Maximum Subarray
- 最长递增子序列 Longest Increasing Subsequence
- Numer of longest increasing subsequence
- Unique Binary Search Trees (catalan number)
1. Make changes using the fewest coins
问题描述:设计算法,得到如何使用零钱,才能使找零的钱总数最少?
数据:
- 硬币类型: Coins[0 -> n -1] eg: Coins = [3, 5, 7] (假设现在又3元,5元,7元这三种面值)
- 找总额为B时所使用的最少硬币数: B[0 -> m] (假设现在需要找零m元)
- 保存分别需要使用哪些硬币: States[](如果不要求详细使用了哪些零钱,则不需要它)
转移方程:
B[i] = min(B[i - 3] + 1, B[i - 5] + 1, B[i - 7] + 1)
(假设要找 i 元,那么最少的硬币数 B[i] 等于 分别使用每一个面额的钞票一次后, 剩下找零所需要的最少硬币数 + 1 ) 注意, 有可能 有的数值无法找零譬如: 找零1元
初始化时,将B所有的值都初始化成None,然后将B[0]初始化成0。
import copy
def problem1(totalnum, coins): # totalnum表示总要找的钱, coins是零钱的类型
states = [] #保存使用了哪些零钱, 当然也可以不在计算时记录用了什么零钱,而在计算到最优结果后回溯寻找
B = [] #保存使用的零钱总数
#初始化
for i in range(totalnum+1):
B.append(None)
states.append([])
B[0] = 0
for i in range(1, totalnum+1):
tempList1 = []
tempList2 = []
for val in coins: #找到min[B[i-1]+1, B[i-5]+1, B[i-8]+1]
if i < val:
B[i] = None
else:
if B[i-val] == None:
pass
else:
tempList1.append(B[i - val] + 1)
tempList2.append(val)
if len(tempList1) == 0:
B[i] = None
else:
#找到钱总数最小值和新加的零钱的value
B[i] = min(tempList1)
index = tempList1.index(B[i])
useVal = tempList2[index]
states[i] = copy.copy(states[i-useVal])
states[i].append(useVal)
print("零钱总数",B[totalnum])
print("使用的零钱", states[totalnum])
problem1(19, [1,5,8])
2. 0-1背包问题
问题描述:使用容量有限的背包装价值不同,体积不同的物品,求如何装才能使得背包里的价值最大?
思路:0-1背包和找零钱的问题,最大的差别在于背包问题里的物品最多只能装一次,而零钱可以使用无限次。
W数组:保存每个物品的体积。
V数组:保存每个物品的价值。
建立F二维数组:来记录每一步的最大价值,方便查表,用空间换时间。
i 第i个物品/j 剩余背包体积 | 0 | 1 | 2 | 3 |
0 | 0 | 0 | 0 | 0 |
1 | 0 | |||
2 | 0 | |||
3 | 0 |
F表的意义: F[i][j]当背包剩余体积是j时,仅考虑前i个物品所能得到的最大价值(前i个物