题目意思是找两个序列的最长公共子序列,并将其打印出来。
题目难点就在于如何将公共序列打印出来。
法1:
此处不能仅通过dp【i】【j】 ==dp【i-1】【j-1】+1就判断s1【i】在公共序列,应先将其他情况排除之后才能判断。
#include <iostream> #include <cstdio> #include <string.h> #include <string> #include <cmath> using namespace std; int dp[101][101]; string tx1[101],tx2[101],seq[101]; int n1,n2; int main() { int t,i,j; string s; while( cin >>s) { n1=n2=0; while( 1) { if( s!="#") tx1[++n1] =s; else break; cin >>s; } while( 1) { cin >>s; if( s!="#") tx2[++n2] =s; else break; } memset( dp, 0,sizeof( dp)); for( i=1; i<=n1; i++) //dp求出最长公共序列长 for( j=1; j<=n2; j++) { if( tx1[i] ==tx2[j] ) dp[i][j] = dp[i-1][j-1] +1; else dp[i][j] =max( dp[i-1][j], dp[i][j-1]); } int ans =dp[n1][n2]; t= ans; while( dp[n1][n2]) //将路径找出来 { if( dp[n1][n2] ==dp[n1-1][n2]) n1--; //先将不是公共序列的情况排除 else if( dp[n1][n2] ==dp[n1][n2-1]) n2--; else { seq[--t] =tx1[n1]; n1--; n2--; } } for( i=0; i<ans; i++) if( !i) printf("%s",seq[i].c_str()); else printf(" %s",seq[i].c_str()); printf("\n"); } return 0; }
法2:
用一个数组P【i】【j】记录下dp在i,j位置时是如何变化的。递归打印出最长公共序列。
#include <iostream> #include <cstdio> #include <string.h> #include <string> #include <cmath> using namespace std; int dp[101][101],p[101][101]; string tx1[101],tx2[101],seq[101]; int n1,n2,flag; void printpath( int a, int b) { if( !a || !b) return ; if( !p[a][b]) { printpath( a-1, b-1); if( !flag) flag =1; else printf(" "); printf("%s",tx1[a].c_str()); } else if( p[a][b] ==-1) printpath( a-1,b); else printpath( a, b-1); } int main() { int t,i,j; string s; while( cin >>s) { n1=n2=0; while( 1) { if( s!="#") tx1[++n1] =s; else break; cin >>s; } while( 1) { cin >>s; if( s!="#") tx2[++n2] =s; else break; } memset( dp, 0,sizeof( dp)); memset( p, 0, sizeof( p)); for( i=1; i<=n1; i++) //dp求出最长公共序列长 for( j=1; j<=n2; j++) { if( tx1[i] ==tx2[j] ) { dp[i][j] = dp[i-1][j-1] +1; p[i][j] =0; } else { dp[i][j] =max( dp[i-1][j], dp[i][j-1]); if( dp[i][j] ==dp[i-1][j]) p[i][j] =-1; else p[i][j] =1; } } flag =0; printpath( n1,n2); printf("\n"); } return 0; }