浅谈动态规划(二)

在算法竞赛中,动态规划的重要性不言而喻。它是所有算法中可以说是最难理解的,也是最难提高的。它范围甚广,变换万千。

所有的关于动态规划的讲解都只是其中的冰山一角,当然,这篇以及后面我要更新的也是。不过在动态规划的世界里,很多人为此沉迷了很多时间,同时也得到了很多理解和感悟。

除了最基础的数塔问题,我们进一步需要学习的分别是DAG、LIS、LCS、LCIS。下面分别进行讲解

DAG
也叫有向无环图,是学习动态规划的基础。很多问题都可以转化为DAG上的最长路、最短路或路径计数问题。

根据紫书上面的总结,DAG的最长路和最短路都可以用记忆化搜索和递推两种实现方式。

由于DAG最长(短)路的特殊性,有两种“对称”的状态定义方式:

状态1: 设d[i]为从i出发的最长路,则d[i]=max(d[j]+1|(i,j)∈E)
状态2: 设d[i]为从i结束的最长路,则d[i]=max(d[j]+1|(i,j)∈E)

多阶段决策问题

多段图是一个特殊的DAG,其结点可以划分成若干个阶段,每个阶段只由上一个阶段所决定。它的最优化问题往往可以用动态规划解决,其中,状态及其转移类似于回溯法中的解答树。解答树中的“层数”,也就是递归函数中的“当前填充位置”cur,描述的是即将完成的决策序号,在动态规划中被称为阶段。

设d[i][j]为到达第i行第j列的最小(最大)花费

每做一次决策就可以得到解得一部分,当所有决策做完之后,完整的解就“浮出水面”了。

LIS

是最长上升子序列的缩写。给定n个整数A1,A2,…,An,按从左到右的顺序选出尽量多的整数,组成一个上升的子序列(子序列可以理解为:删除0个或者多个数,其他数的顺序不变),例如序列:1,6,2,3,7,5,可以选出上升子序列1,2,3,5,也可以选出1,6,7,但前者更长。注意,选出的上升子序列中相邻元素不能相等。

设d[i]为以i结尾的最长上升子序列的长度

可以得到状态转移方程:

d[i]=max(0,d[j]|j

最后遍历一次,答案为

max(d[i])

如果LIS中的元素可以相等,把小于号改成小于等于号即可。

LCS
全称叫做最长公共子序列问题。给定两个子序列A和B,求长度最大的公共子序列。

设d[i][j]为A1,A2,...,Ai和B1,B2,...Bj的LCS长度

则分成两种情况来讨论:

(1)a[i] == b[j]时     d[i][j] = d[i-1][j-1]+1;
(2)a[i] != b[j]时     d[i][j] = max(d[i-1][j],d[i][j-1]);

LCIS
是增加的一个内容,叫做最长递增公共子序列。

设d[i][j]为以a串的前i项和b串的前j项且以b[j]为结尾构成的LCIS的长度

同时也可以分成两种情况来讨论:

(1)a[i] == b[j]时    d[i][j] = max+1;
(2)a[i] >  b[j]时    max = max(max,d[i-1][j]);

如果想要更简单一点,可以在维度上进行优化:

(1)a[i] == b[j]时    d[j]  max+1;
(2)a[i] >  b[j]时     max = max(max,d[j]+1);

推荐题目:

UVa10635

UVa11584

UVa10534

UVa11404

UVa116

UVa10891

hdu1234

hdu1421

hdu1257

hdu1159

hdu5904

poj1088

poj2247

poj1159

题解有时间就会来补充。

你可能感兴趣的:(ACM,算法笔记,算法细讲(ACM))