最长公共子序列
这两天都在看基础的动态规划,讲到最长公共子序列的时候,想起了很多以前做过的OJ上的题,但是当时想法太差只会暴力循环而且没做对,所以话了点时间整理
《算法导论》中第十五章说:一个给定序列的子序列就是该给定序列中去掉0个或者多个元素。以形式化的方式来说,给定一个序列X=X[1],X[2].....X[m],另一个序列Z=Z[1],Z[2].....Z[k]是X的子序列,如果存在X的一个严格递增下标序列<i1,i2.....ik>,使得对所有的j=1 2.....k有X[i]=Z[j]。
例子:Z=BCDB 是X=ABCBDAB的一个子序列,相对应的下标序列为2 3 5 7
给定两个序列X和Y,如果Z既是X的一个子序列,又是Y的一个子序列,则称序列Z是X和Y的公共子序列(这里我觉得中文版翻译的顺序错了,所以我改了下句子的顺序)。
例子是:假设两个字符串X,Y X="ABCBDAB" Y="BDCABA"
则他们的最大公共子序列 是"BCBA"
这个问题可以用动态规划来解决
#include<stdio.h> #include<string.h> void turn(char A[],char tA[]) //将A复制放在tA,不过tA的0位置是没东西 { //比如说 A :ABCDEFG\0 int len=strlen(A); //那么tA变成: ABCDEFG\0 tA[0]=' '; //这样做的原因是 数组下标从0开始 for(int i=0;i<len;i++) //所以将A[1]要变成字符的开头 { tA[i+1]=A[i]; } tA[len+1]='\0'; } void LCSlength(char A[],char B[],int c[][50],int b[][50]) //c数组是记录 记录公共子序列的长度 { int lena=strlen(A)-1,lenb=strlen(B)-1; for(int i=0;i<=lena;i++)c[i][0]=0; for(int i=0;i<=lenb;i++)c[0][i]=0; for(int i=1;i<=lena;i++) { for(int j=1;j<=lenb;j++) { if(A[i]==B[j]) //当遇到能够构成更长的子序列的时候+1 { 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]=0; } } } } void printLCS(int b[][50],char A[],int i,int j) //输出最长公共子序列 { if(i==0||j==0)return ; if(b[i][j]==1) { printLCS(b,A,i-1,j-1); printf("%c",A[i]); } else if(b[i][j]==2)printLCS(b,A,i-1,j); else printLCS(b,A,i,j-1); } void printMArray(int Array[][50],int x,int y) //监控b / c数组的过程 { for(int i=1;i<=x;i++) { for(int j=1;j<=y;j++) { printf("%d ",Array[i][j]); } printf("\n"); } } int main() { printf("请输入要求最长公共子序列的两个字符串:\n"); char A[50],B[50]; char tA[50],tB[50]; int b[50][50],c[50][50]; scanf("%s %s",A,B); int lenA=strlen(A); int lenB=strlen(B); turn(A,tA); turn(B,tB); LCSlength(tA,tB,c,b); printMArray(c,lenA,lenB); //printMArray(b,lenA,lenB); printLCS(b,tA,lenA,lenB); return 0; }
posted on 2012-11-25 18:29 Aquariuslt 阅读(142) 评论(0) 收藏 举报
浙公网安备 33010602011771号