动态规划
2016-12-15 14:39
288 查看
动态规划
最大连续子序列和
从O(N^3)到O(N)问题: 给定一个序列, 求出最大连续的子序列和.
穷举算法 O(N^3)
python codeL = [-2, 11, -4, 13, -5, -2] N = len(L) max_sum = L[0] for begin in range(N): for end in range(begin, N): sum = 0 for i in range(begin, end+1): sum += L[i] if sum > max_sum: max_sum = sum print(max_sum)
递进算法 O(N^2)
python codeL = [-2, 11, -4, 13, -5, -2] N = len(L) max_sum = L[0] for begin in range(N): sum = 0 for i in range(begin, N): sum += L[i] if sum > max_sum: max_sum = sum print(max_sum)
分治算法 O(NlogN)
python codeL = [-2, 11, -4, 13, -5, -2] N = len(L) def max_sum(low, high): if high-low == 1: return L[low] # get mid between low and high mid = low + (high-low)//2 # return max sum of 2 parts maxz = max(max_sum(low, mid), max_sum(mid, high)) # left sum left_sum = L[mid-1] sum, i = 0, mid-1 while i >= low: sum += L[i] left_sum = max(left_sum, sum) i -= 1 # right sum right_sum = L[mid] sum, i = 0, mid while i < high: sum += L[i] right_sum = max(right_sum, sum) i += 1 # return max sum mid_sum = left_sum + right_sum return max(maxz, mid_sum) ans = max_sum(0, N) print(ans)
动态规划 O(N)
状态方程: MaxSum[i]=max(MaxSum[i-1]+L[i], L[i])python code
L = [-2, 11, -4, 13, -5, -2] N = len(L) DP = [0 for i in range(N)] max_sum = DP[0] = L[0] for i in range(1, N): if DP[i-1]+L[i] >= L[i]: DP[i] = DP[i-1] + L[i] else: DP[i] = L[i] max_sum = max(max_sum, DP[i]) print(max_sum)
贪心算法 O(N)
python codeL = [-2, 11, -4, 13, -5, -2] N = len(L) max_sum = L[0] sum = 0 for i in range(1, N): sum += L[i] max_sum = max(max_sum, sum) if sum < 0: sum = 0 print(max_sum)
数数字
从递归到递推问题: 从0开始, 可以加上1, 也可以加上2, 递归此步骤, 一直加到正好是N的方案有多少种?
DFS O(2^N)
直接搜索式python code
CNT = 0 N = 10 def dfs(cur): if cur > N: return if cur == N: global CNT CNT += 1 return dfs(cur+1) dfs(cur+2) dfs(0) print(CNT)
累加返回式
python code
N = 10 def dfs(cur): cnt = 0 if cur > N: return 0 if cur == N: return 1 cnt += dfs(cur+1) cnt += dfs(cur+2) return cnt ans = dfs(0) print(ans)
递归定义式
python code
def dfs(cur): if cur==1 or cur==2: return cur return dfs(cur-1)+dfs(cur-2) ans = dfs(10) print(ans)
记忆化搜索 O(N)+?
用DP数组来保存已搜索过的当前节点搜索结果, 防止重复向下搜索.累加返回式
python code
N = 10 C = [-1 for i in range(N+1)] def dfs(cur): if cur > N: return 0 if cur == N: return 1 if C[cur] != (-1): return C[cur] C[cur] = 0 C[cur] += dfs(cur+1) C[cur] += dfs(cur+2) return C[cur] ans = dfs(0) print(ans)
递归定义式
状态方程: dp[i]=dp[i-1]+dp[i-2]
python code
N = 10 C = [-1 for i in range(N+1)] C[1], C[2] = 1, 2 def dp(cur): if C[cur] != (-1): return C[cur] C[cur] = dp(cur-1) + dp(cur-2) return C[cur] ans = dp(10) print(ans)
递推(动态规划) O(N)
状态方程: dp[i]=dp[i-1]+dp[i-2]根据递归定义式的状态方程直接递推
F列表中保存的结果正好是一个斐波那契数列
N = 10 F = [0 for i in range(N+1)] F[1], F[2] = 1, 2 for i in range(3, N+1): F[i] = F[i-1] + F[i-2] print(F )
状态方程的转换
数塔
图如下A
/ \
B C
/ \ / \
D E F
问题: 从顶层走到底层(不能回头), 每步只能走到相邻的结点, 求经过的结点的数字的最大和.
状态方程: T[i][j] = max(DP[i][j]+DP[i+1][j], DP[i][j]+DP[i+1][j+1])
N = 5 DP = [ [7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5] ] for i in range(N-2, -1, -1): for j in range(i+1): DP[i][j] += max(DP[i+1][j], DP[i+1][j+1]) print(DP[0][0])
圆盘摆物
问题: 一个圆被分为3个区域A, B, C, 有一个物品在A区域, 一次可以把物品拿起来摆放在其他区域, 不能在原区域摆放, 这个步骤执行N次, 要求最后物品还是摆放在A区域, 有多少种方法?状态方程如下
A[i] = B[i-1]+C[i-1]
B[i] = A[i-1]+C[i-1]
C[i] = A[i-1]+B[i-1]
化简后的状态方程如下
A[i] = 2A[i-2]+A[i-1]
python code
N = 10 A = [0 for i in range(N+1)] A[1], A[2] = 0, 2 for i in range(3, N+1): A[i] = 2*A[i-2] + A[i-1] print(A )
最大公共子序列
问题: 求2个字符串的最大公共子序列长度(元素不要求连续, 只含英文字母).状态方程如下
L[i][j] = 0 if i==0 or j==0
L[i][j] = L[i-1][j-1] + 1 if str[i] == str[j]
L[i][j] = max(L[i-1][j], L[i][j-1]) if str[i] != str[j]
python code
S1 = "_ACBDEFGH" S2 = "_ABCEGDH" N, M = len(S1), len(S2) DP = [[0 for j in range(M)] for i in range(N)] for i in range(1, N): for j in range(1, M): if S1[i] == S2[j]: DP[i][j] = DP[i-1][j-1] + 1 elif S1[i] != S2[j]: DP[i][j] = max(DP[i-1][j], DP[i][j-1]) print(DP[N-1][M-1])
背包问题
0-1背包
问题: 有n个物品和1个背包, 物品i的重量是wi, 价值为vi, 背包的容量(重量)为C, 如何选择装入背包的物品使得装入背包中物品的总价值最大?状态方程如下
DP[i][w] = max(DP[i-1][w], DP[i-1][w-W[i]]+V[i]) if w>=W[i]
DP[i][w] =DP[i-1][w] if w小于W[i]
python code
N, C = 5, 10 W = [0, 4, 1, 3, 4, 6] V = [0, 4, 2, 7, 8, 6] DP = [[0 for j in range(C+1)] for i in range(N+1)] for i in range(1, N+1): for j in range(1, C+1): if W[i] <= j: DP[i][j] = max(DP[i-1][j], DP[i-1][j-W[i]]+V[i]) else: DP[i][j] = DP[i-1][j] print(DP [C])
完全背包
问题: 有n种物品(物品有无限个)和1个背包, 物品i的重量是wi, 价值为vi, 背包的容量(重量)为C, 如何选择装入背包的物品使得装入背包中物品的总价值最大?状态方程: DP[i][w] = max(DP[i][w], DP[i-1][w], DP[i-1][w-W[i]*k]+V[i]*k)
python code
N, C = 5, 10 W = [0, 4, 2, 6, 5, 4] V = [0, 4, 2, 5, 4, 6] DP = [[0 for j in range(C+1)] for i in range(N+1)] for i in range(1, N+1): for j in range(1, C+1): for k in range(j//W[i]+1): DP[i][j] = max(DP[i][j], DP[i-1][j], DP[i-1][j-W[i]*k]+V[i]*k) print(DP [C])
多重背包
问题: 有n种物品(物品各有Ai(Ai>0)个)和1个背包, 物品i的重量是wi, 价值为vi, 背包的容量(重量)为C, 如何选择装入背包的物品使得装入背包中物品的总价值最大?状态方程: DP[i][w] = max(DP[i][w], DP[i-1][w], DP[i-1][w-W[i]*k]+V[i]*k)
python code
N, C = 5, 10 W = [0, 4, 2, 6, 5, 4] V = [0, 4, 3, 5, 4, 6] A = [0, 1, 2, 3, 2, 1] DP = [[0 for j in range(C+1)] for i in range(N+1)] for i in range(1, N+1): for j in range(1, C+1): for k in range(min(j//W[i], A[i])+1): DP[i][j] = max(DP[i][j], DP[i-1][j], DP[i-1][j-W[i]*k]+V[i]*k) print(DP [C])
背包问题优化
01背包的优化在二维数组中计算的状态可以用一维数组覆盖计算, 并省去j小于W[i]的情况.
python code
N, C = 5, 10 W = [0, 4, 1, 3, 4, 6] V = [0, 4, 2, 7, 8, 6] F = [0 for i in range(C+1)] for i in range(1, N+1): for j in range(C, W[i]-1, -1): F[j] = max(F[j], F[j-W[i]]+V[i]) print(F[C])
完全背包的优化
使用覆盖计算, 省去j小于W[i]的情况, 顺序计算第i个物品K个的价值.
python code
N, C = 5, 10 W = [0, 4, 1, 3, 4, 6] V = [0, 4, 2, 7, 8, 6] F = [0 for i in range(C+1)] for i in range(1, N+1): for j in range(W[i], C+1): F[j] = max(F[j], F[j-W[i]]+V[i]) print(F[C])
多重背包的优化
将第i种物品分成n个独立物品的组合(转为01背包问题), 利用二进制分解优化, 再进行覆盖计算.
python code
N, C = 5, 10 W = [0, 4, 2, 6, 5, 4] V = [0, 4, 3, 5, 4, 6] A = [0, 1, 2, 3, 2, 1] for i in range(N): k, cnt = 2, A[i]-1 while k <= cnt: W.append(k*W[i]) V.append(k*V[i]) cnt -= k k <<= 1 N += 1 if cnt > 0: W.append(cnt*W[i]) V.append(cnt*V[i]) N += 1 F = [0 for i in range(C+1)] for i in range(1, N+1): for j in range(C, W[i]-1, -1): F[j] = max(F[j], F[j-W[i]]+V[i]) print(F[C])
相关文章推荐
- 动态规划
- 最大子段和,二分法变异,动态规划
- HDU2571 命运 动态规划
- 剑指:斐波纳契数列动态规划求解
- 算法导论-第15章-动态规划:钢条切割问题自底向下方法C++实现
- 动态规划——背包问题笔记
- EOJ 1825 【动态规划】
- 【动态规划】最少硬币换取目标钱数【0-1背包问题】
- HDU2151 Worm 动态规划
- (动态规划)最长回文子序列、回文子序列个数
- Palindrome(poj1159)(动态规划)
- BZOJ 1875 [SDOI2009]HH去散步 ——动态规划 矩阵乘法
- 动态规划分析总结——如何设计和实现动态规划算法
- 动态规划(1)数字三角形
- (3)最大子段和问题____动态规划
- hdu4939(动态规划)
- BZOJ 1270 Beijing Wc 2008 雷涛的小猫 动态规划
- 动态规划
- hdu1494 跑跑卡丁车 (动态规划)
- 算法提高 概率计算(动态规划)