基本题一:最长公共子序列问题

一、实验目的与要求

1、熟悉最长公共子序列问题的算法;

2、初步掌握动态规划算法;

二、实验题

    若给定序列X={x1,x2,,xm},则另一序列Z={z1,z2,,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,,ik}使得对于所有j=1,2,,k有:zj=xij。例如,序列Z={BCDB}是序列X={ABCBDAB}的子序列,相应的递增下标序列为{2357}

给定2个序列XY,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列XY的公共子序列。

给定2个序列X={x1,x2,,xm}Y={y1,y2,,yn},找出XY的最长公共子序列。

 

三、实验提示

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-1xm-1yn-1的最长公共子序列。

 

   (2)xmynzkxm,则Zxm-1Y的最长公共子序列。(即:ZX序列中前m个元素所组成的序列与Y序列的最长公共子序列)

 

   (3)xmynzkyn,则ZXyn-1的最长公共子序列。(即:ZY序列中前n个元素所组成的序列与X序列的最长公共子序列)

 

由上面三个条件可得如下公式:

C[][]用来记录最长公共子序列的长度,则:

c[i][j] = <1> 0;                   (ij = 0)

 

<2> c[i-1][j-1] + 1;        (ij > 0 Xi = Yj)(即第iX序列元素与第jY元素相等)

 

<3> max(c[i][j-1] , c[i-1][j])       (ij > 0 Xi != Yj)(当XiYj不等时,取两个式子的最大值,若两者相等则默认取第一个)

 

五,源代码

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


 

结果: