最大公共子序列问题-动态规划-c语言实现

什么是最大公共子序列?

子序列为父序列的0~n个子集,但必须按父序列的顺序(例如ABCBDAB的子序列可为A、B、AB、AAB....),他和字串的区别是,字串子集必须是连续的

最大公共子序列是多个序列的公共子序列最大长度(例如:ABCBDAB和BDCABA的最大公共子序列大小为4,BCBA、BDAB、BCAB都是最大公共子序列)


 最长公共子序列的长度为c[i,j],递归式如下:

最大公共子序列问题-动态规划-c语言实现_第1张图片

序列1:0ABCBDAB

  序列2:0BDCABA

 下图为递归子问题的各个最长公共子序列的长度

我白话的讲解一下这个怎么求

例如第四行,第七列的2是怎么求出的

他对应的行是D,列是D,他们是相等的,他的值就等于他的左上角(第3行,第6列)的值加一,即1+1=2

如果不相等就判断他的上面的值和左边的值的大小,取最大的那个

例如第7行,第6列的3是怎么求出的

他对应的行是B,列是A,他们是不相等的,上面的值为3,左边的值为2,3>2,所以取3

0 A B C B D A B
0 0 0 0 0 0 0 0 0
B 0 0 1 1 1 1 1 1
D 0 0 1 1 1 2 2 2
C 0 0 1 2 2 2 2 2
A 0 1 1 2 2 2 3 3
B 0 1 2 2 3 3 3 4
A 0 1 2 2 3 3 4 4

他的时间复杂度为O(n*m)

#include 
#include 
#include 

int **c;  //二维数组指针,存放递归求出的各最大公共子序列个数

int Get_Max_Num_Sequence(char a[], char b[], int i, int j){
    if (c[j][i] != 0)  //表中有数据,直接查表,减少重复操作
    {
        return c[j][i];  
    }
    
    if(i == 0 || j == 0){
        c[j][i] = 0;
    }else if (a[i] == b[j])
    {
        c[j][i] = Get_Max_Num_Sequence(a, b, i-1, j-1) + 1;
    }
    else{
        int g = Get_Max_Num_Sequence(a, b, i-1, j);
        int h = Get_Max_Num_Sequence(a, b, i, j-1);
        if(g > h){
            c[j][i] = g;
        }else{
            c[j][i] = h;
        }
    }
    return c[j][i];
}

int Max_Num_Sequence(char a[], char b[]){
    //动态分配二数组空间
    c = (int **)calloc(strlen(b), sizeof(int *));
    for (int i = 0; i < strlen(b); i++)
    {
       c[i] = (int *)calloc(strlen(a), sizeof(int));
    }
    
    return Get_Max_Num_Sequence(a, b, strlen(a)-1, strlen(b)-1);
}

void show(char a[], char b[], int i, int j){
    if(c[j][i] == 0){
        printf("\n");
        return;
    }

    if(a[i] == b[j]){
        show(a, b, i-1, j-1);
        printf("%c", a[i]);
    }else{
        if(c[j][i-1] >= c[j-1][i]){
            show(a, b, i-1, j);
        }else{
            show(a, b, i, j-1);
        }
    }
    
}

int main(void){
    char a[] = "0ABCBDAB";
    char b[] = "0BDCABA";
    printf("最大公共子序列数:%d\n", Max_Num_Sequence(a, b));

    for (int j = 0; j < strlen(b); j++)
    {
        for (int i = 0; i < strlen(a); i++)
        {
            printf("%d  ", c[j][i]);
        }
        printf("\n");
    }

    printf("其中一条子序列为:");
    show(a, b, strlen(a)-1, strlen(b)-1);
    
    return 0;
}

结果:

最大公共子序列问题-动态规划-c语言实现_第2张图片

 

你可能感兴趣的:(算法,动态规划,算法)