1 / 114

Dynamic Programming

Dynamic Programming. 目录. DP 适用问题第一特征:重叠子问题 Fibonacci Number Binomial Coefficients Shortest paths in DAGs DP 适用问题第二特征:最优子结构 Chain matrix multiplication Longest Increasing Subsequences 运用 DP 解决问题的步骤. 目录. DP 问题分类 Knapsack 背包问题 Edit Distance The Partition Problem. 简介.

fisk
Download Presentation

Dynamic Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Dynamic Programming

  2. 目录 • DP适用问题第一特征:重叠子问题 • Fibonacci Number • Binomial Coefficients • Shortest paths in DAGs • DP适用问题第二特征:最优子结构 • Chain matrix multiplication • Longest Increasing Subsequences • 运用DP解决问题的步骤

  3. 目录 • DP问题分类 • Knapsack 背包问题 • Edit Distance • The Partition Problem

  4. 简介 • DP是在20世纪50年代由一位卓越的美国数学家Richcard Bellman发明的。它作为一种重要的工具在应用数学中被广泛的应用。它不仅可以解决特定类型的优化问题,还可以作为一种通用的算法设计技术为计算机服务。

  5. DP适用问题的第一特征 • 所求解的问题具有重叠子问题。 • 解决方法 • 进行记忆化求解。(用空间换时间) • 依照某种合适次序计算,以避免重复计算。

  6. Fibonacci Number • 求Fibonacci数: f(n) = f(n-1) + f(n-2) n>1 f(0)=0, f(1)=1

  7. Fibonacci Number • 常规递归 long long fib_r(int n) { if (n == 0) return 0; if (n == 1) return 1; return (fib_r(n-1) + fib_r(n-2)); } • 指数级时间复杂度,无法忍受。

  8. Fibonacci Number • 常规递归 • 重叠子问题,导致重复计算。

  9. Fibonacci Number • 自顶而下,记忆化求解 long longfib_c(int n) { if (f[n] == -1) f[n] = fib_c(n-1) + fib_c(n-2); return (f[n]); } long longfib_c_driver(int n) { f[0] = 0; f[1] = 1; for (inti=2; i<=n; i++) f[i] = -1; return (fib_c(n)); }

  10. Fibonacci Number • 自底而上,顺序求解 long long fib_dp(int n) { long long f[MAXN + 1]; f[0] = 0; f[1] = 1; for (int i=2; i<=n; i++) f[i] = f[i-1] + f[i-2]; return (f[n]); }

  11. Fibonacci Number • 自底而上,顺序求解。空间优化 long longfib_ultimate(int n) { /* back2,back1 are last two values of f[n] */ long long back2 = 0, back1 = 1; long long next; if (n==0) return 0; for (inti=2; i<n; i++) { next = back1 + back2; back2 = back1; back1 = next; } return (back1+back2); }

  12. Binomial Coefficients • C(n,k)表示从n个不同物体中选出k个的组合数 • C(n,k)=n!/((n−k)!k!)=C(n-1,k-1)+C(n-1,k) Pascal’s triangle Matrix representation

  13. Binomial Coefficients Const int MAXN = 100; long long binomial_coefficient(int n, int k) { long long bc[MAXN+1][MAXN+1]; for (int i = 0; i<=n; i++) bc[i][0] = 1; for (int j = 0; j<=n; j++) bc[j][j] = 1; for (int i = 1; i<=n; i++) for (int j=1; j<i; j++) bc[i][j] = bc[i-1][j-1] + bc[i-1][j]; return ( bc[n][k] ); }

  14. Shortest paths in DAGs 以S为源点对左图中的所有结点进行拓扑排序,得到右图。则计算从源点S到点D的最短路径可以表示为: dist(D) = min{dist(B)+edge(BD), dist(C)+edge(CD)} = min{dist(B)+1, dist(C)+3} 这里的B和C是结点D的两个前驱结点。

  15. Shortest paths in DAGs Topologically sort vertices in G; Initialize all dist(.) values to INF dist(s) = 0 for each v ∈ V , in linearized order do dist(v) = min(u,v) ∈E { dist(u) + w(u,v) }

  16. Example 6 1 u r t s v w 2 7 –2 5 –1  0     4 3 2

  17. Example 6 1 u r t s v w 2 7 –2 5 –1  0     4 3 2

  18. Example 6 1 u r t s v w 2 7 –2 5 –1  0 2 6   4 3 2

  19. Example 6 1 u r t s v w 2 7 –2 5 –1  0 2 6 6 4 4 3 2 dist[u]=min{dist[s]+6, dist[t]+7}

  20. Example 6 1 u r t s v w 2 7 –2 5 –1  0 2 6 5 4 4 3 2

  21. Example 6 1 u r t s v w 2 7 –2 5 –1  0 2 6 5 3 4 3 2

  22. Example 6 1 u r t s v w 2 7 –2 5 –1  0 2 6 5 3 4 3 2

  23. 动态规划术语 • 状态:贴切,简洁的描述出事物性质的单元量。例如:Dist[x]。 要求:状态与状态之间可以转移,以便有初始状态逐渐转移到目标状态,找到问题的解。 • 阶段:若干性质相近可以同时处理的状态的集合。就是计算状态的顺序。 要求:每个阶段中状态的取值只与这个阶段之前的阶段中的状态有关,与这个阶段之后的阶段中的状态无关。

  24. 动态规划术语 • 状态转移方程:前一个阶段中的状态转移到后一个阶段的状态得演变规律,即相邻两个阶段的状态变化方程。 Dk(i) = opt { Dk-1(j) + cost(i,j) } k阶段的i状态与k-1阶段的j状态有关 • 决策:计算每个状态时作出的选择。

  25. 动态规划时间效率 动态规划解决问题的方法是通过解决很多小的问题而解决大问题。 动态规划的效率取决于两个因素:子问题的数量和子问题的解决效率。 时间效率:子问题的数量*子问题的时间效率。

  26. DP适用问题的第二特征 • 所求解的问题具有最优子结构,即问题的一个最优解中包含子问题的最优解。 • 例如,Ai×Ai+1×…×Aj的一个最优加全部括号把乘积在和之间分裂,它包含了两个子问题Ai×Ai+1×…×Ak和Ak+1×Ak+2×…×Ak的最优解。

  27. Chain matrix multiplication

  28. Chain matrix multiplication

  29. Chain matrix multiplication For 1≤ i≤k≤j ≤n, define C(i,j) = minimum cost of multiplying Ai×Ai+1×…×Aj for i = 1 to n: C(i, i) = 0 for s = 1 to n - 1: for i = 1 to n - s: j = i + s C(i, j) = min{C(i, k) + C(k + 1, j) +mi-1·mk·mj : i≤k ≤j} return C(1, n) The subproblems constitute a two-dimensional table, each of whose entries takes O(n) time to compute. The overall running time is thus O(n3).

  30. Chain matrix multiplication • 矩阵链相乘问题具有最优子结构,即问题的一个最优解中包含子问题的最优解。 • Ai×Ai+1×…×Aj的一个最优加全部括号把乘积在和之间分裂,它包含了两个子问题Ai×Ai+1×…×Ak和Ak+1×Ak+2×…×Ak的最优解。

  31. 相关习题 sicily1345 能量项链

  32. 运用DP解决问题的步骤 • 找出问题的最优子结构,并判断是否具有子问题重叠性。 • 合理设计状态,递归的定义最优解。 • 使用恰当的计算顺序,计算出最优值。 • 根据计算最优值过程中的信息,递归的构造一个最优解。

  33. Longest Increasing Subsequences

  34. Longest increasing subsequence • Algorithm:

  35. Longest Increasing Subsequences L(0) = 1, P(.) = -1 For i = 1, 2, …, n L(i) = 1 + max0<j<i{L(j)}, where Sj<Si P(i) = j L(i) is the length of the longest path ending at i (plus 1). Time complexity is O(n2), the maximum being when the input array is sorted in increasing order.

  36. 相关习题 • 推荐题目: sicily1060 Bridging Signals (需要用特殊法做) sicily1685 Missile(最长不单调子序列,数据小,O(n2)) sicily1448 Antimonotonicity(最长不单调子序列,数据大,O(n))

  37. 背包问题 • 01背包问题 • 完全背包问题 • 多重背包问题 • 分组的背包问题 • 有依赖的背包问题

  38. 01背包问题 • 有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。 • 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 • 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。

  39. 对于“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。对于“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。 • 如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v]; • 如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。 • 状态转移方程: f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

  40. 时间复杂度O(NV) • 由于计算f[i][v]时只用到f[i-1][v]和f[i-1][v-c[i]],在每次主循环中我们以v=V..0的顺序推f[v],这样就保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值,f[v]保存的是状态f[i-1][v]的值。 • 伪代码如下: for i=1..N for v=V..0 f[v]=max{f[v], f[v-c[i]] + w[i]}; • 空间复杂度成功降到O(V)

  41. 抽象成过程ZeroOnePack,表示处理一件01背包中的物品,两个参数cost、weight分别表明这件物品的费用和价值。抽象成过程ZeroOnePack,表示处理一件01背包中的物品,两个参数cost、weight分别表明这件物品的费用和价值。 void ZeroOnePack(cost,weight){ for v=V..cost f[v]=max{f[v],f[v-cost]+weight} } • 01背包问题的伪代码就可以这样写: for i=1..N ZeroOnePack(c[i],w[i]);

  42. 初始化问题 • 如果题目要求“恰好装满背包”时的最优解 在初始化时除了f[0]为0其它f[1..V]均设为-∞ • 如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0 • 初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。

  43. 推荐题目: sicily1146 采药 sicily1342 开心的金明 sicily1782 Knapsack

  44. 完全背包问题 • 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 • 状态转移方程 f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i] | 0<=k*c[i]<=v} • 时间复杂度O(V*Σ(V/c[i])),太大。

  45. 转化为01背包问题求解 • 第i种物品最多选V/c[i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品 • 没有改进时间复杂度 • 采用二进制思想: 把第i种物品拆成费用为c[i]*2k、价值为w[i]*2k的若干件物品,其中k满足c[i]*2k ≤ V。不管最优策略选几件第i种物品,总可以表示成若干个2k件物品的和。这样把每种物品拆成O(log V/c[i])件物品 • 时间复杂度O(V*Σ(log V/c[i])),很大的改进

  46. O(VN)的算法 使用一维数组,伪代码: for i=1..N for v=0..V f[v]=max{f[v],f[v-cost]+weight} void CompletePack(int cost,int weight) { for(int v=cost;v<=V;++v) f[v] >?= f[v-cost]+weight; }

  47. 01背包按照v=V..0的逆序来循环,要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。01背包按照v=V..0的逆序来循环,要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。 • 完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。即f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}

  48. 多重背包问题 • 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 • 状态转移方程: f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i] | 0≤k ≤ n[i]} • 复杂度是O(V*Σn[i])。

  49. 转化为01背包问题 采用二进制思想: 将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为1,2,4,...,2k-1,n[i]-2k+1,且k是满足n[i]-2k+1>0的最大整数。例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。 • 将第i种物品分成了O(log n[i])种物品, • 时间复杂度O(V*Σlog n[i])

  50. for(inti=0;i<N;i++) MultiplePack(c[i],w[i],n[i]); void MultiplePack(cost,weight,amount) { if cost*amount>=V CompletePack(cost,weight) return for(int k=1; k<amount; k++) ZeroOnePack(k*cost,k*weight) amount=amount-k k=k*2 ZeroOnePack(amount*cost,amount*weight) }

More Related