动态规划---最长公共子序列
2015-07-25 13:22
302 查看
看完算法导论关于这部分内容之后的总结:
关于最长公共子序列问题:
给定两个子序列 X=<X1, X2, X3 , .... , Xm > ; Y=<Y1, Y2, Y3 ,..., Yn>,求X和Y长度最长的公共子序列。
解决方法:
首先先要了解LCS的最优子结构,令X=<X1, X2, X3 , .... , Xm > ; Y=<Y1, Y2, Y3 ,..., Yn>为两个子序列,Z = <Z1,Z2,... ,Zk>为X和Y的任意LCS。
1、如果 Xm = Yn , 则 Zk = Xm = Yn 且 Zk-1 是 Xm-1 和 Yn-1 的一个LCS;
2、如果 Xm ≠ Yn , 则 Zk ≠ Xm ,意味着 Z 是Xm-1和Y 的一个LCS;
3、如果 Xm ≠ Yn , 则 Zk ≠ Yn ,意味着 Z 是X和Yn-1 的一个LCS;
求解最长公共子序列主要用到以下公式
伪代码分析
LCS_LENGTH(X,Y)
1、 m = X.length
2、 n = Y.length
3、 for i = 1 to m
4、 c[i,0] = 0 //c[][]计算表项
5、 for j =0 to m
6、 c[0,j] = 0
7、 for i = 1 to m
8、 for j = 1 to n
9、 if Xi == Yj //先比较Xi 和 Yj 是否相等
10、 c[i,j] = c[i-1][j-1] + 1 //相等的话就将c[i,j]的值加上其上一个对角线元素的值
11、 b[i,j] = "↖" //并将当前单元格设置成"↖"
12、 elseif c[i-1][j] ≥ c[i][j-1] //Xi 和 Yj 不相等,则比较当前单元格上方和左方单元格的值
13、 c[i,j] = c[i-1][j] //如果上方单元格的值大于等于其左方单元格的值,则当前单元格设置成"↑"
14、 b[i][j] = "↑"
15、 else
16、 c[i][j] = c[i][j-1]
17、 b[i][j] = "←" //否则设置成"←"
18、return c and b
根据以上伪代码构造出的表
执行4,5行后得到下面这个表:
然后以行为主序开始扫描:
我们可以先找出 Xi == Yj 的单元格,标记它的值和箭头方向 。
当i = 1时,扫描第一行中为(A,A)的单元格,标记为↖,并执行c[i][j] = c[i-1][j-1] + 1;
其它的单元格按照12-17行的代码进行标记,如(X1,Y1) = (A,B),两者不相同,所以比较(X1,Y1)上方和左方的单元格的值。哪个的值大,箭头就指向哪个单元格,并将c[i][j]的值设置为c[i-1,j],c[i,j-1]中具有较大值的单元格的值。
当 i = 2时,按照以上方法进行单元格赋值。
。。。。
最后得到以下表格:
↑
得到上面的表格之后,执行以下函数得到LCS
PRINT-LCS(b, X, X.length, Y.length)
1、if X.length==0 || Y.length == 0
2、 return;
3、if b[i,j] == "↖"
4、 PRINT-LCS(b, X, X.length-1, Y.length-1)
5、 print Xi
6、elseif b[i,j] == "↑"
7、 PRINT-LCS(b, X, X.length-1, Y.length)
8、else
9、 PRINT-LCS(b, X, X.length, Y.length-1)
关于最长公共子序列问题:
给定两个子序列 X=<X1, X2, X3 , .... , Xm > ; Y=<Y1, Y2, Y3 ,..., Yn>,求X和Y长度最长的公共子序列。
解决方法:
首先先要了解LCS的最优子结构,令X=<X1, X2, X3 , .... , Xm > ; Y=<Y1, Y2, Y3 ,..., Yn>为两个子序列,Z = <Z1,Z2,... ,Zk>为X和Y的任意LCS。
1、如果 Xm = Yn , 则 Zk = Xm = Yn 且 Zk-1 是 Xm-1 和 Yn-1 的一个LCS;
2、如果 Xm ≠ Yn , 则 Zk ≠ Xm ,意味着 Z 是Xm-1和Y 的一个LCS;
3、如果 Xm ≠ Yn , 则 Zk ≠ Yn ,意味着 Z 是X和Yn-1 的一个LCS;
求解最长公共子序列主要用到以下公式
伪代码分析
LCS_LENGTH(X,Y)
1、 m = X.length
2、 n = Y.length
3、 for i = 1 to m
4、 c[i,0] = 0 //c[][]计算表项
5、 for j =0 to m
6、 c[0,j] = 0
7、 for i = 1 to m
8、 for j = 1 to n
9、 if Xi == Yj //先比较Xi 和 Yj 是否相等
10、 c[i,j] = c[i-1][j-1] + 1 //相等的话就将c[i,j]的值加上其上一个对角线元素的值
11、 b[i,j] = "↖" //并将当前单元格设置成"↖"
12、 elseif c[i-1][j] ≥ c[i][j-1] //Xi 和 Yj 不相等,则比较当前单元格上方和左方单元格的值
13、 c[i,j] = c[i-1][j] //如果上方单元格的值大于等于其左方单元格的值,则当前单元格设置成"↑"
14、 b[i][j] = "↑"
15、 else
16、 c[i][j] = c[i][j-1]
17、 b[i][j] = "←" //否则设置成"←"
18、return c and b
根据以上伪代码构造出的表
执行4,5行后得到下面这个表:
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ||||||
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |
我们可以先找出 Xi == Yj 的单元格,标记它的值和箭头方向 。
当i = 1时,扫描第一行中为(A,A)的单元格,标记为↖,并执行c[i][j] = c[i-1][j-1] + 1;
其它的单元格按照12-17行的代码进行标记,如(X1,Y1) = (A,B),两者不相同,所以比较(X1,Y1)上方和左方的单元格的值。哪个的值大,箭头就指向哪个单元格,并将c[i][j]的值设置为c[i-1,j],c[i,j-1]中具有较大值的单元格的值。
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |
。。。。
最后得到以下表格:
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ↖1 | ←1 | ←1 | ↑1 | ↖2 | ←2 |
3 | C | 0 | ↑1 | ↑1 | ↖2 | ←2 | ↑2 | ↑2 |
4 | B | 0 | ↖1 | ↑1 | ↑2 | ↑2 | ↖3 | ←3 |
5 | D | 0 | ↑1 | ↖2 | ↑2 | ↑2 | ↑3 | ↑3 |
6 | A | 0 | ↑1 | ↑2 | ↑2 | ↖3 | ↑3 | ↖4 |
7 | B | 0 | ↖1 | ↑2 | ↑2 | ↑3 | ↖4 |
得到上面的表格之后,执行以下函数得到LCS
PRINT-LCS(b, X, X.length, Y.length)
1、if X.length==0 || Y.length == 0
2、 return;
3、if b[i,j] == "↖"
4、 PRINT-LCS(b, X, X.length-1, Y.length-1)
5、 print Xi
6、elseif b[i,j] == "↑"
7、 PRINT-LCS(b, X, X.length-1, Y.length)
8、else
9、 PRINT-LCS(b, X, X.length, Y.length-1)
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |
相关文章推荐
- 猜数游戏
- [MFC]CEdit编辑框类
- 【面试加分项】运行时多态与编译时多态
- COJN 0486 800401反质数 呵呵呵呵呵
- DNS主从复制及区域传送
- 小白学开发(iOS)OC_匿名对象(2015-07-24)
- 使用TCP/IP的套接字(Socket)进行通信
- hdu5289 单调队列
- win32编成入门-位图
- iOS中如何显示一张图片
- 倒序输出(如输入456则输出654)
- HDU 2674-- N!Again【技巧】
- OJ常见问题及必须认识的对拍处理水题
- NodeJS+Express开发web,为什么中文显示为乱码
- java新手笔记20 抽象类模板(letter)
- css3仿山猫侧边栏
- J - Borg Maze - poj 3026(BFS+prim)
- Redis key 设计技巧
- SAP,IBM,AC实施之比较
- 第一个驱动程序之中断处理