基本题一:最长公共子序列问题
一、实验目的与要求
1、熟悉最长公共子序列问题的算法;
2、初步掌握动态规划算法;
二、实验题
若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
三、实验提示
include "stdlib.h" #include "string.h" void LCSLength(char *x ,char *y,intm,int n, int **c, int **b) { inti ,j; for (i = 1; i<= m; i++) c[i][0] = 0; for (i = 1; i<= n; i++) c[0][i] = 0; for (i = 1; i<= m; i++) for (j = 1; j <= n; j++) { if (x[i]==y[j]) { c[i][j]=c[i-1][j-1]+1; b[i][j]=1; } else if (c[i-1][j]>=c[i][j-1]) { c[i][j]=c[i-1][j]; b[i][j]=2; } else { c[i][j]=c[i][j-1]; b[i][j]=3; } } } void LCS(inti ,int j, char *x ,int **b) { if (i ==0 || j==0) return; if (b[i][j]== 1) { LCS(i-1,j-1,x,b); printf("%c",x[i]); } else if (b[i][j]== 2) LCS(i-1,j,x,b); else LCS(i,j-1,x,b); }
四、题目分析
在求最长公共子序列中,我们可以看出如下规律:
设序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列为Z={z1,z2,…,zk} ,则
(1)若xm=yn,则zk=xm=yn,且zk-1是xm-1和yn-1的最长公共子序列。
(2)若xm≠yn且zk≠xm,则Z是xm-1和Y的最长公共子序列。(即:Z是X序列中前m个元素所组成的序列与Y序列的最长公共子序列)
(3)若xm≠yn且zk≠yn,则Z是X和yn-1的最长公共子序列。(即:Z是Y序列中前n个元素所组成的序列与X序列的最长公共子序列)
由上面三个条件可得如下公式:
C[][]用来记录最长公共子序列的长度,则:
c[i][j] = <1> 0; (当i、j = 0时);
<2> c[i-1][j-1] + 1; (当i、j > 0 且 Xi = Yj时)(即第i个X序列元素与第j个Y元素相等)
<3> max(c[i][j-1] , c[i-1][j]) (当i、j > 0 且 Xi != Yj时)(当Xi与Yj不等时,取两个式子的最大值,若两者相等则默认取第一个)
五,源代码
importjava.util.*; import java.io.*; public class LCS { public static void main(String[] args) { String s1 = "ABCBDAB"; String s2 = "BDCABA"; LCS cms = new LCS(); String[] x = cms.init(s1); String[] y = cms.init(s2); int[][] b = new int[x.length][y.length]; System.out.println("最大子序列的长度为:"+lcsLength(x, y, b)); System.out.println("最大子序列为:"); lcs(x.length-1, y.length-1, x, b); } public static void lcs(inti, int j, String[] x, int[][] b) { if (i == 0 || j == 0) return; if (b[i][j] == 1) { lcs(i - 1, j - 1, x, b); System.out.print(x[i]+" "); } else if (b[i][j] == 2) lcs(i - 1, j, x, b); else lcs(i, j - 1, x, b); } private String[] init(String str){ String temp = str; String[] s = temp.split(""); return s; } public static intlcsLength(String[] x, String[] y, int[][] b) { int m = x.length - 1; int n = y.length - 1; int[][] c = new int[m + 1][n + 1]; for (inti = 1; i<= m; i++){ c[i][0] = 0; } for (inti = 1; i<= n; i++) c[0][i] = 0; for (inti = 1; i<= m; i++) { for (int j = 1; j <= n; j++) { if (x[i].equals(y[j])) { c[i][j] = c[i - 1][j - 1] + 1; b[i][j] = 1; } else if (c[i - 1][j] >= c[i][j - 1]) { c[i][j] = c[i - 1][j]; b[i][j] = 2; } else { c[i][j] = c[i][j - 1]; b[i][j] = 3; } } } return c[m][n]; } }
结果: