题目意思是找两个序列的最长公共子序列,并将其打印出来。
题目难点就在于如何将公共序列打印出来。
法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;
}