110
Dynamic Programming

Dynamic Programming

  • Upload
    raanan

  • View
    64

  • Download
    0

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: Dynamic Programming

Dynamic Programming

Page 2: Dynamic Programming

目录 DP适用问题第一特征:重叠子问题

Fibonacci Number Binomial Coefficients Shortest paths in DAGs

DP适用问题第二特征:最优子结构 Chain matrix multiplication Longest Increasing Subsequences

运用 DP解决问题的步骤

Page 3: Dynamic Programming

目录 DP经典问题

Knapsack 背包问题 硬币问题 树状 DP Edit Distance The Partition Problem

Page 4: Dynamic Programming

简介 动态规划 (Dynamic Programming, DP)是在

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

Page 5: Dynamic Programming

DP适用问题的第一特征 所求解的问题具有重叠子问题。 解决方法

进行记忆化求解。(用空间换时间) 依照某种合适次序计算,以避免重复计算。

Page 6: Dynamic Programming

Fibonacci Number

求 Fibonacci数:f(n) = f(n-1) + f(n-2) n>1

f(0)=0, f(1)=1

Page 7: Dynamic Programming

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));} 指数级时间复杂度,无法忍受。

Page 8: Dynamic Programming

Fibonacci Number 常规递归

重叠子问题,导致重复计算。

Page 9: Dynamic Programming

Fibonacci Number 自顶而下,记忆化求解long long fib_c(int n){ if (f[n] == -1) f[n] = fib_c(n-1) + fib_c(n-2); return (f[n]);}

long long fib_c_driver(int n){ f[0] = 0; f[1] = 1; for (int i=2; i<=n; i++) f[i] = -1; return (fib_c(n));}

Page 10: Dynamic Programming

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]);}

Page 11: Dynamic Programming

Fibonacci Number 自底而上,顺序求解。空间优化long long fib_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 (int i=2; i<n; i++) { next = back1 + back2; back2 = back1; back1 = next; } return (back1+back2);}

Page 12: Dynamic Programming

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 triangleMatrix representation

Page 13: Dynamic Programming

Binomial CoefficientsConst 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] );}

Page 14: Dynamic Programming

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的两个前驱结点。

Page 15: Dynamic Programming

Shortest paths in DAGs

Topologically sort vertices in G;Initialize all dist(.) values to INFdist(s) = 0for each v ∈ V , in linearized order do

dist(v) = min(u,v) E∈ { dist(u) + w(u,v) }

Page 16: Dynamic Programming

Example

0 r s t u v w

5 2 7 –1 –2

6 1

32

4

求 s到任意点的最短距离

Page 17: Dynamic Programming

Example

0 r s t u v w

5 2 7 –1 –2

6 1

32

4

dist[r] = , dist[s] = 0

Page 18: Dynamic Programming

Example

0 2 6 r s t u v w

5 2 7 –1 –2

6 1

32

4

Page 19: Dynamic Programming

Example

0 2 6 6 4r s t u v w

5 2 7 –1 –2

6 1

32

4

dist[t]=min{dist[s]+2, dist[r]+3}

Page 20: Dynamic Programming

Example

0 2 6 5 4r s t u v w

5 2 7 –1 –2

6 1

32

4

dist[u]=min{dist[s]+6, dist[t]+7}

Page 21: Dynamic Programming

Example

0 2 6 5 3r s t u v w

5 2 7 –1 –2

6 1

32

4

dist[v]=min{dist[t]+4, dist[u]-1}

Page 22: Dynamic Programming

Example

0 2 6 5 3r s t u v w

5 2 7 –1 –2

6 1

32

4

dist[w]=min{dist[t]+2, dist[u]+1, dist[v]-2}

Page 23: Dynamic Programming

动态规划术语 状态:贴切,简洁的描述出事物性质的单元量。例如:

Dist[x]。要求:状态与状态之间可以转移,以便有初始状态逐渐转移到目标状态,找到问题的解。 阶段:若干性质相近可以同时处理的状态的集合。就是计算状态的顺序。要求:每个阶段中状态的取值只与这个阶段之前的阶段中的状态有关,与这个阶段之后的阶段中的状态无关。

Page 24: Dynamic Programming

动态规划术语 状态转移方程:前一个阶段中的状态转移到后一个阶段的状态得演变规律,即相邻两个阶段的状态变化方程。

Dk(i) = opt { Dk-1(j) + cost(i,j) }第 k阶段的 i状态与第 k-1阶段的 j状态有关

决策:计算每个状态时作出的选择。

Page 25: Dynamic Programming

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

Page 26: Dynamic Programming

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

Ak+1×Ak+2×…×Ak的最优解。

Page 27: Dynamic Programming

Chain matrix multiplication

Page 28: Dynamic Programming

Chain matrix multiplication

Page 29: Dynamic Programming

Chain matrix multiplication

for i = 1 to n: C(i, i) = 0for 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)

For 1≤ i≤k≤j ≤n, define

C(i,j) = minimum cost of multiplying Ai×Ai+1×…×Aj

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).

Page 30: Dynamic Programming

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

×Ak和 Ak+1×Ak+2×…×Ak的最优解。

Page 31: Dynamic Programming

相关习题sicily1345 能量项链

给出一串项链,每次可以选相邻两个珠子进行聚合,释放出一定的能量,并产生一个新珠子。项链是头尾相接的。求释放的能量的总和的最大值。 项链长度不超过 100。

Page 32: Dynamic Programming

Longest Increasing Subsequences

Page 33: Dynamic Programming

Longest increasing subsequence Algorithm:

Page 34: Dynamic Programming

Longest Increasing Subsequences

L(0) = 1, P(.) = -1For 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.

Position i 1 2 3 4 5 6 7 8Sequence Si 5 2 8 6 3 6 9 7

Length Li 1 1 2 2 2 3 4 4Predecessor Pi -1 -1 1 1 2 5 6 6

Page 35: Dynamic Programming

Longest Increasing Subsequences

Position i 1 2 3 4 5 6 7 8

s[i] 5 2 8 6 3 6 9 7

l[i] 1 1 2 2 2 3 4 4

p[i] -1 -1 1 1 2 5 6 6

Page 36: Dynamic Programming

相关习题 推荐题目:

sicily1060 Bridging Signals (需要用特殊法做)sicily1685 Missile(最长不单调子序列,数据小, O(n2))sicily1448 Antimonotonicity(最长不单调子序列,数据大, O(n))

Page 37: Dynamic Programming

小结 动态规划的一般步骤

考察问题结构,给出状态表示方式,列出递归方程(状态转移方程) 分析复杂度,若复杂度较高则需要优化。 用递推或记忆化搜索实现。 根据计算最优值过程中的信息,递归的构造一个最优解。

应用动态规划的前提条件1. 重复子问题2. 最优子结构

Page 38: Dynamic Programming

经典问题

Page 39: Dynamic Programming

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

Page 40: Dynamic Programming

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

v的背包可以获得的最大价值,其状态转移方程为 f[i][v]=max{ f[i-1][v], f[i-1][v-c[i]]+w[i] }。 复杂度分析:

状态数: O(NV), 迁移: O(1) 总复杂度: O(NV)

Page 41: Dynamic Programming

状态 f[i][v]表示前 i 件物品恰放入一个容量为 v的背包可以获得的最大价值。 对于“将前 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] }

Page 42: Dynamic Programming

时间复杂度 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)

Page 43: Dynamic Programming

抽象成过程 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]);

Page 44: Dynamic Programming

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

Page 45: Dynamic Programming

推荐题目:sicily1782 Knapsack

sicily1146 采药sicily1342 开心的金明

Page 46: Dynamic Programming

完全背包问题 有 N种物品和一个容量为 V的背包,每种物品都有无限件可用。第 i种物品的费用是

c[i],价值是 w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 状态 f[i][v]表示前 i 件物品恰放入一个容量为 v的背包可以获得的最大价值,其状态转移方程为

f[i][v]=max{ f[i-1][v], f[i][v-c[i]]+w[i] } 时间复杂度 O(NV)

Page 47: Dynamic Programming

O(VN)的算法空间优化,伪代码:for i=1..N for v=0..V

f[v]=max{f[v],f[v-c[i]]+w[i]}

void CompletePack(int cost,int weight){ for(int v=cost;v<=V;++v) f[v] >?= f[v-cost]+weight;}

完全背包问题

Page 48: Dynamic Programming

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]}

Page 49: Dynamic Programming

二维背包 对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价;对于每种代价都有一个可付出的最大值(背包容量) . 问怎样选择物品可以得到最大的价值 . 设第 i 件物品所需的两种代价分别为 a[i]和 b[i]. 两种代价可付出的最大值(两种背包容量)分别为 V和 U. 物品的价值 w[i]. 分析:费用加了一维,只需状态也加一维即可 . 设 f[i][v][u]表示前 i 件物品付出两种代价分别为 v和 u时可获得的最大价值。状态转移方程就是: f[i][v][u]=max{ f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i] }

Page 50: Dynamic Programming

二维背包 二维背包很容易扩展到多维背包 “二维费用”的条件有时是以这样一种隐含的方式给出的:最多只能取M 件物品 . 这事实上相当于每件物品多了一种“件数”的费用,每个物品的件数费用均为 1,可以付出的最大件数费用为M.

Page 51: Dynamic Programming

多重背包问题 有 N种物品和一个容量为 V的背包。第 i种物品最多有 n[i] 件可用,每件费用是 c[i],价值是 w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 转化为二维背包求解。

Page 52: Dynamic Programming

推荐题目poj1014 Dividingsicily1077 Cash Machine(可能不算多重背包,不过可采用类似方法 )

Page 53: Dynamic Programming

分组背包 有 N 件物品和一个容量为 V的背包。第 i 件物品的费用是 c[i],价值是 w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 分析:这个问题变成了每组物品有若干种策略:是选择本组中的某一件,还是一件都不选。设 f[k]

[v]表示前 k组物品花费费用 v能取得的最大权值,则有状态转移方程:f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i] | 物品 i属于组k}

Page 54: Dynamic Programming

使用一维数组的伪代码如下:for 所有的组 k for v=V..0 for 所有的 i 属于组 k f[v]=max{f[v],f[v-c[i]]+w[i]}

注意这里的三层循环的顺序“for v=V..0”这一层循环必须在“ for 所有的 i 属于组 k”之外。这样才能保证每一组内的物品最多只有一个会被添加到背包中

Page 55: Dynamic Programming

推荐题目:sicily1750 运动会

Page 56: Dynamic Programming

有依赖的背包问题 物品间存在某种“依赖”的关系, i依赖于 j,表示若选物品 i,则必须选物品 j。设没有某个物品既依赖于别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多件物品。 可以对主件 i的“附件集合”先进行一次 01 背包,得到费用依次为 0..V-c[i]所有这些值时相应的最大价值 f'[0..V-c[i]]。那么这个主件及它的附件集合相当于 V-c[i]+1个物品的物品组,其中费用为 c[i]+k的物品的价值为 f'[k]+w[i]。也就是说原来指数级的策略中有很多策略都是冗余的,通过一次 01 背包后,将主件 i转化为 V-c[i]+1个物品的物品组,分组背包。

Page 57: Dynamic Programming

推荐题目:sicily1346 金明的预算方案

Page 58: Dynamic Programming

推荐资料 Tianyi Cui 《背包九讲》,可在课程页面上下载。 推荐书籍:刘汝佳等《算法艺术与信息学竞赛》(俗称“黑书”) 1.5 节 动态规划

Page 59: Dynamic Programming

最大字段和问题 最大子段和问题:给定由 n个整数 (可能为负整数 )组成的序列 a1,a2,…,an,求该序列形如的 子段和的最大值。

j

ik

ka ][

Page 60: Dynamic Programming

设 bi为到 ai 截至且包括 ai的字段最大和。 bi = bi-1 + ai bi-1>0

ai bi-1<=0 b1 = a1

ans = max{ bi }

Page 61: Dynamic Programming

ans=b=a[1];for(i=2;i<=n;i++){

if (b>0) b+=a[i]; else b=a[i];if (b>ans) ans=b;

}

Page 62: Dynamic Programming

引申问题:最大子矩阵和问题最大m段子段和问题 推荐题目:

poj1050 To the Max(最大子矩阵和问题)sicily1091 Maximum Sum(最大m段子段和问题)sicily1888 Circular Sequence (求一次最大MAX,判断是否是整个串,如果是就求一次最小MIN,然后MAX-MIN就是最后解,否则MAX就是解)

Page 63: Dynamic Programming

硬币问题 1 有 n种硬币,每种硬币的面值为 c[i]元,且只有一枚,问用这 n种硬币找零 s元的方法数。 设 d[i][j]为前 i种硬币组成 j元的方法数。

d[i][j] = d[i-1][j] + d[i-1][ j-c[i] ]d[0][0]=1,d[0][1…s]=0

若用 top_down 实现,空间复杂度为 O(n2) 。 若用 bottom_up 实现,空间复杂度可为

O(n) 。

Page 64: Dynamic Programming

硬币问题 1

d[0]=1; d[1…s]=0;for (i=1; i<=n; i++) {

for (j=s; j>=c[i]; j--){

      d[j] += d[j-v[i]];  }}

Page 65: Dynamic Programming

硬币问题 2

有 n种硬币,每种硬币的面值为 c[i] 元,有m[i] 枚,问用这 n种硬币找零 s元的方法数。d[0]=1;d[1…s]=0;for (i=1; i<=n; i++) {

for (j=s; j>=c[i]; j--){ for(k=1;k<=m[i];k++){ if (j-k*c[i]>=0)

d[j] += d[j-k*c[i]]; else break; }

  }}

Page 66: Dynamic Programming

硬币问题 3 有 n种硬币,每种硬币的面值为 c[i]元,有无数枚,问用这 n种硬币找零 s元的方法数。

d[0]=1;d[1…s]=0;for (i=1; i<=n; i++) {

for (j=s; j>=c[i]; j--){

for(k=1;;k++){      if (j-k*c[i]>=0) d[j] += d[j-k*c[i]];

else break;}

  }}

Page 67: Dynamic Programming

硬币问题 3

d[0]=1; d[1…s]=0;for (i=1; i<=n; i++) {

for (j=c[i];j<=s; j++){

      d[j] += d[j-c[i]];  }}

Page 68: Dynamic Programming

硬币问题 4 有 n种硬币,面值分别为 v[1], v[2], …, v[n],每种有无限多。给定非负整数 s, 可以选用多少个硬币,使得面值之和恰好为 s? 输出硬币数目的最小值和最大值。 1 ≤ n ≤ 100, 0 ≤ s ≤ 10000, 1 ≤

v[i] ≤ s. 问题可转化为 DAG上的路径问题。把每种面值看做一个点,表示“还需要凑够的面值”,则初始状态为 s,目标状态为 0。若当前在状态 i,每使用一个硬币 j,状态便转移到 i-v[j].

Page 69: Dynamic Programming

硬币问题 4 以 d(i)记“从结点 i出发到结点 0的最长路径长度”。memset(vis,0,sizeof(vis));memset(d,0,sizeof(d));int dp(int s)

{if(vis[s]) return d[s];vis[s] = 1;int& ans = d[s];ans = -INF; // INF = 1<<30for(int i=1;i<=n;i++)

if(s>=v[i]) ans >?= dp(s-v[i]) + 1;

return ans;}

Page 70: Dynamic Programming

硬币问题 4 输出字典序最小的方案。void print_ans(int *d, int s)

{ for(int i=1; i<=n; i++)

if (s>=v[i] && d[s]==d[s-v[i]]+1){

printf(“%d “, i);print_ans(d, s-v[i]);break;

}}

Page 71: Dynamic Programming

硬币问题 4 递推的写法,同时求min和max。min[0] = max[0] = 0;for(int i=1; i<=s; i++) {

min[i]=INF; max[i]=-INF;}for(int j=1; j<=n; j++)

for(int i=1; i<=s; i++) if( i>=v[j]) {

min[i] <?= min[i-v[j]] + 1;max[i] >?= max[i-v[j]] + 1;

}cout << min[s] << “ “ << max[s] << endl;

Page 72: Dynamic Programming

相关习题sicily 2014 Dairy Queensicily1005 Roll Playing Games(此题为搜索题,里面得先 dp一次)sicily1564 HOUSING(可看成硬币问题)sicily1902 Counting Problem

Page 73: Dynamic Programming

数字三角形问题 给定一个具有 N 层的数字三角形,从顶至底有多条路径,每一步可沿左斜线向下或沿右斜线向下,路径所经过的数字之和为路径得分,请求出最小路径得分。

2 6 2 1 8 4 1 5 6 8 数字三角形

Page 74: Dynamic Programming

用二元组 D(x,y)描述问题, D(x,y)表示从第 x层第 y个位置到达底层的最小路径得分。 最优子结构性质:显然, D(x,y)的最优路径

Path(x,y)一定包含子问题 D(x+1,y) 或D(x+1,y+1)的最优路径

递归关系: D(x,y) = min{D(x+1,y),D(x+1,y+1)}+a(x,y) D(n,k) = a(n,k), k = 1,…, n

其中, a(x,y)为第 X 层第 y个位置的数值。 D(x,y)表示从第 X 层第 y个位置到达底层的最小路径得分。原问题的最小路径得分即为 D(1,1)

数字三角形问题

Page 75: Dynamic Programming

相关习题 sicily1563 GECKO

Page 76: Dynamic Programming

凸多边形的三角形剖分 给定一个凸多边形 P={v0,v1,…vn-1} ,以及定义在由凸多边形的边和弦组成的三角形上的权函数 w。要求确定该凸多边形的一个三角划分,使得该三角划分中诸三角形上权之和为最小。

Page 77: Dynamic Programming

凸多边形的三角形剖分 最优子结构

状态转移方程t[i,i]=0t[i,j] = mini<=k<j{t[i,k]+t[k,j]+w(vivkvj)}参考题目: HOJ 1714 Minimax Triangulation

Page 78: Dynamic Programming

sicily 1822 决斗 编号从 1-n的 n个人按逆时针方向排成一圈,他们要决斗 n-1 场,其中第 i个人与第 i+1个人决斗(如果 i=n则与第一个人决斗),死者退出圈子,紧靠死者右边的人成为与赢者直接相邻的人。任意两人之间决斗的胜负都将在一矩阵中给出(如果 A[i,j]=1,则 i与 j决斗时, i总是赢,如果

A[i,j]=0,则 i总是输),求所有可能赢得整场决斗的人的序号

Page 79: Dynamic Programming

分析:假设需要判断 x是否能赢得整场决斗,把环看成链,x点拆成两个,那编号为 x的人能从所有人中胜出的充分必要条件是他能与自己相遇,这样在连续几个人的链中,只需考虑头尾两个人是否能胜利会师,中间的则不予考虑,设meet[i,j]记录 i和 j是否相遇,能为 1,否则为 0,问题转化为能否找到一个 k,使得 i和 k能相遇, k和 j能相遇,且 i或者 j能够打败 k。

状态转移方程:存在 i<k<j 使得meet[i,k] 且 meet[k,j] 且( A[i,k] 或 A[j,k]) ,则meet[i,j]=1,否则meet[i][j]=0。 时间复杂度 O(n3),空间复杂度 O(n2)。

决斗

Page 80: Dynamic Programming

树形动态规划 树型 dp,即在树结构上做 dp。由于树的结构本身是一种递归结构,比较简单,单路连通,具有很优的状态转移结构。 很多在一般图上是 NP 难的问题,在树结构上存在多项式时间的 DP算法。如图着色问题,最小点覆盖问题。 必要条件:子树之间不可以相互干扰,如果本来是相互干扰的,那么我们必须添加变量使得他们不相互干扰。 题目的一般出法是父节点状态由子树状态决定 .所以,算法实现通常借助 DFS过程。

Page 81: Dynamic Programming

Party at Hali-Bula n个人形成一个关系树,每个节点代表一个人,节点的根表示这个人的唯一的直接上司,只有根没有上司。要求选取一部分人出来,使得每 2个人之间不能有直接的上下级的关系,求最多能选多少个人出来,并且求出获得最大人数的选人方案是否唯一。 这是一个经典的树型动态规划。

Page 82: Dynamic Programming

Party at Hali-Bula

简单的染色统计是不正确的

Page 83: Dynamic Programming

Party at Hali-Bula

人之间的关系形成树型结构 状态: 用 dp[i][0]表示不选择 i点时, i点及其子树能选出的最多人数; dp[i][1]表示选择 i点时, i点及其子树的最多人数。

Page 84: Dynamic Programming

Party at Hali-Bula

状态转移方程 : 对于叶子节点 i, dp[i][0] = 0, dp[i][1] = 1 对于非叶子节点 i,

dp[i][0] = ∑max(dp[j][0], dp[j][1]) (j是 i的儿子 )dp[i][1] = 1 + ∑dp[j][0] (j是 i的儿子 )

最多人数即为max(dp[0][0], dp[0][1])

Page 85: Dynamic Programming

Party at Hali-Bula 如何判断最优解是否唯一 ? 新加一个状态 dup[i][j],表示相应的 dp[i][j]是否是唯一方案。 对于叶子结点 i, dup[i][0] = dup[i][1] = 1. 对于非叶子结点 ,

对于 i的任一儿子 j,若(dp[j][0] > dp[j][1] && dup[j][0] == 0) || (dp[j][0] < dp[j][1] && dup[j][1] == 0) || (dp[j][0] == dp[j][1]),则 dup[i][0] = 0

对于 i的任一儿子 j, 若 dup[j][0] == 0, 则 dup[i][1] = 0

Page 86: Dynamic Programming

Strategic game

一城堡的所有的道路形成一个 n个节点的树,如果在一个节点上放上一个士兵,那么和这个节点相连的边就会被看守住,问把所有边看守住最少需要放多少士兵。 典型的树型动态规划

Page 87: Dynamic Programming

Strategic game dproot[ i ]表示以 i为根的子树,在 i上放置一个士兵,看守住整个子树需要多少士兵。 all[ i ]表示看守住整个以 i为根的子树需要多少士兵。 状态转移方程: 叶子节点 i: dproot[i] =1 ; all[i] = 0 ; 非叶子节点 i: dproot[i] = 1 + ∑all[j] (j是 i的儿子 ) ; all[i] = min( dproot[i], ∑dproot[j](j是 i的儿子 ) ) ;

Page 88: Dynamic Programming

Strategic game

这个题目还是比较简单的,如果把题目中看守边变成看守相邻的点呢?留给你来思考 ^_^

Page 89: Dynamic Programming

状态压缩动态规划 状态压缩动态规划: 动态规划的状态有时候不容易表示出来,需要用一些编码技术,把状态压缩的用简单的方式表示出来。 典型方式:当需要表示一个集合有哪些元素时,往往利用 2进制用一个整数表示。 对于集合 S={0,1, 2, …, N- 1} ,在 N 较小的情况下, S的子集 A可以用一个 N位二进制数 x 来表示 . 表示方法:当 i 属于 A时, x 的第 i 位为 1 ;否则为 0. 例如:当 N=16时,集合 A={2, 3, 5} ,可以表示为

x=00101100,即十进制整数 44.

Page 90: Dynamic Programming

经典问题: TSP 一个 n个点的带权的有向图,求一条路径,使得这条路经过每个点恰好一次,并且路径上边的权值和最小(或者最大)。 或者求一条具有这样性质的回路,这是经典的

TSP问题。 n <= 16 (重要条件 ,状态压缩的标志 )

Page 91: Dynamic Programming

TSP 如何表示一个点集: 由于只有 16个点,所以我们用一个整数表示一个点集: 例如: 5 = 0000000000000101 ;( 2进制表示) 它的第 0位和第 2位是 1,就表示这个点集里有 2个点,分别是点 0和点 2。 31 = 0000000000011111 ; ( 2进制表示) 表示这个点集里有 5个点,分别是

0, 1, 2, 3, 4 ;

Page 92: Dynamic Programming

TSP

所以一个整数 i就表示了一个点集; 整数 i可以表示一个点集,也可以表示是第 i个点。 状态: dp[i][j]表示经过点集 i中的点恰好一次,不经过其它的点,并且以 j点为终点的路径,权值和的最小值,如果这个状态不存在,就是无穷大。

Page 93: Dynamic Programming

TSP 状态转移 单点集:状态存在 dp[i][j] = 0 ;否则无穷大。非单点集: 状态存在 dp[i][j] = min(dp[k][s] + w[s][j]), s k∈ k表示 i集合中去掉了 j点得到的集合, s是集合 k中的点并且 dp[k][s]状态存在, 点 s到点

j有边存在, w[s][j]表示边 <s,j>的权值。 状态不存在 ,则 dp[i][j]为无穷大。

Page 94: Dynamic Programming

TSP 最后的结果是: min( dp[( 1<<n ) – 1][j] ) ( 0 <= j < n ) ; 技巧:利用 2进制,使得一个整数表示一个点集,这样集合的操作可以用位运算来实现。• 判断点 j 是否属于集合 i : i & (1<<j)• 在集合 i 中去除点 j : i –(1<<j) 或者 i & ( ~( 1 << j ) ) • 在集合 i 中加入点 j : i | (1<<j)

Page 95: Dynamic Programming

状态压缩DP:图的最长路相关题目: sicily 1123. The Longest Walk参考代码 s1123.c• 问题描述:给出一个带权有向图 G=(V, E),求图中的一条最长简单路径 . • 如果暴力穷举所有路径,复杂度不低于O(N!)

Page 96: Dynamic Programming

动态规划方程• 状态表示:用 ans[j][i]表示以 j点为起点,并且经过点集 i中的点恰好一次而不经过其它点的路径长度的最大值 . 如果这个状态不存在,就是无穷小 .• 状态转移:如果点集 i 只包含一个点, ans[j][i] = 0 , j∀ ;否则, ans[j][i] = max(w[j][k] + ans[k][s])s 表示 i 集合中去掉了 j点的集合, k 遍历集合s 中的点,点 j 到点 k 有边存在, w[j][k]表示边(j, k) 的权值 .• 最后结果便是所有 ans[j][i]的最大值 .

Page 97: Dynamic Programming

多阶段决策问题 跳舞机( ACM Regional Contest Shanghai

2000)

Page 98: Dynamic Programming

跳舞机 Moving one of his feet from the central point to any side

points will consume 2 units of his strength. Moving from one side point to another adjacent side point will consume 3 units, such as from the top point to the left point. Moving from one side point to the opposite side point will consume 4 units, such as from the top point to the bottom point. Yet, if he stays on the same point and tread again, he will use 1 unit.

Page 99: Dynamic Programming

跳舞机 状态:

d[i][j][k]为跳到第 k个舞步时,左脚在位置 i,右脚在位置 j时所需要耗费的最少体力 状态转移方程 :

d[i,j,k]=min{ d[s[k],j,k+1]+cost(i,s[k]), d[i,s[k],k+1]+cost(j,s[k]) }

d[i,j,n]=min{ cost(i,s[n]), cost(j,s[n]) }最优值为 d[i,j,1]

Page 100: Dynamic Programming

Longest Common Substring

Page 101: Dynamic Programming

Longest Common Substring 状态: 记 Xi = (x1,x2,…,xi), Yi = (y1,y2,…,yi)

c[i][j]记录序列 Xi和 Yj的最长公共子序列的长度。 状态转移方程 :

c(i, j) = 0 if i=0 or j=0c(i, j) = c(i-1, j-1) + 1 if i, j>0 and xi = yj

c(i, j) = max{c(i,j-1), c(i-1,j)}if i, j>0 and xi ≠ yj

Page 102: Dynamic Programming

Edit Distance When a spell checker encounters a possible misspelling, it looks in

its dictionary for other words that are close by. What is the appropriate notion of closeness in this case?

A natural measure of the distance between two strings is the extent to which they can be aligned, or matched up. Technically, an alignment is simply a way of writing the strings one above the other. For instance, here are two possible alignments of SNOWY and SUNNY:S – N O W Y – S N O W – Y S U N N – Y S U N – – N YCost: 3 Cost: 5

The ' – ' indicates a 'gap'; any number of these can be placed in either string. The cost of an alignment is the number of columns in which the letters differ. And the edit distance between two strings is the cost of their best possible alignment.

Page 103: Dynamic Programming

Edit Distance Our goal is to find the edit distance between two strings

x[1…m] and y[1…n]. What is a good subproblem? How about looking at the edit distance between some

prefix x of the first string, x[1…i], and some prefix of the second, y[1…j]? Call this subproblem E(i, j). Our goal objective, then, is to compute E(m, n).

Page 104: Dynamic Programming

Edit Distance For this to work, we need to somehow express E(i, j) in

terms of smaller subproblems. Let's see what do we know about the best alignment �

between x[1…i] and y[1…j]? Well, its rightmost column can only be one of three things:

E(i, j) = min{1 + E(i-1, j), 1 + E(i, j-1), diff(i, j) + E(i-1, j-1)}where diff(i, j) is defined to be 0 if x[i] = y[j] and 1 otherwise.

Page 105: Dynamic Programming

Edit Distance For instance, in computing the edit distance between

EXPONENTIAL and POLYNOMIAL, subproblem E(4, 3) corresponds to the prefixes EXPO and POL. The rightmost column of their best alignment must be one of the following:

Thus, E(4, 3) = min{1 + E(3, 3), 1 + E(4, 2), 1 + E(3, 2)}.

Page 106: Dynamic Programming

Edit Distance The answers to all the subproblems E(i, j) form a two-

dimensional table.

Page 107: Dynamic Programming

Edit Distance The algorithm for edit distance:

The overall running time is just the size of the table, O(mn).

Page 108: Dynamic Programming

总结 实质:

重叠子问题,最优子结构,记忆化求解,空间换时间 两种实现方式:

自底向上 (bottom up) 自顶向下 (top down)

基本概念 状态 阶段 状态转移方程 决策

Page 109: Dynamic Programming

问题分类: 零维状态存储问题 一维状态存储问题 二维状态存储问题 树状 DP 状态压缩 DP 多阶段决策问题

Page 110: Dynamic Programming

sicily上的一些 dp题:sicily1010 Zipper sicily1011 Lenny's Lucky Lotto sicily1019 Apple Tree (树型 dp)sicily1057 Rhyme Schemes sicily1073 Pearls sicily1123 The Longest Walk(状态压缩 dp)sicily1148 过河(路径压缩,贪心动态规划)sicily1158 Pick numbers sicily1222 单词选择(这题的 hash很恶心)sicily1264 Atomic Car Race (基本 dp题)sicily1404 Hie with the Pie(状态压缩 dp) sicily1687 Permutationsicily1822 Fight Clubsicily1828 Minimal