题意:求最大公共子序列,并按字典序输出最大子序列。
题解:题目的难点在于输出。看了http://www.cppblog.com/varg-vikernes/archive/2010/09/27/127866.html
1.用 pos1[ i ] [ j ] 代表字符 'a'+j 在 s1 中第 i 个字符前最后出现的位置 ( 即 1 -- i 这个范围内,最后出现的位置 )。
若字符 'a' + j 不存在,那么pos1 [ i ] [ j ] = 0;
pos2 同理。
2.枚举最长公共子序列的每一个字符。假设最长公共子序列的长度为 cnt, s1 长度为 l1, s2 长度为 l2。 我们先确定第 cnt 个字符, dfs ( l1, l2, cnt )。
它可能是 a, b, c, ····,z 的其中之一。假设是 a, 那么需要找出 a 在 s1 及 a在 s2 中最后出现的位置 pos1 [ l1 ] [ 0 ], pos2 [ l2 ] [ 0 ], 令 p1 = pos1[l1][0], p2 = pos2[l2][0]。 若 dp[p1][p2] == cnt ,那么 ans [ cnt ] = a,
在此基础上枚举第 cnt - 1 个字符, dfs ( p1 - 1, p2 - 1, cnt - 1 )。·····最终找到第 1 个字符,结束。
#include <queue>
#include <iostream>
using namespace std;
#define N 85
char s1[N], s2[N];
int dp[N][N], pos1[N][30], pos2[N][30];
struct item { char str[N]; } com;
bool operator> ( const item &a, const item &b )
{
if ( strcmp ( a.str, b.str ) > 0 )
return true;
return false;
}
priority_queue<item, vector<item>, greater<item> > que;
int max ( int a, int b )
{
return a > b ? a : b;
}
void dfs ( int l1, int l2, int c )
{
if ( c < 1 )
{
que.push ( com );
return;
}
if ( l1 < 1 || l2 < 1 ) return;
for ( int i = 0; i < 26; i++ )
{
int t1 = pos1[l1][i]; /* pos1[l1][i] 代表字符 'a'+i 在 s1 中最后出现的位置 */
int t2 = pos2[l2][i]; /* pos2[l2][i] 代表字符 'a'+i 在 s2 中最后出现的位置 */
if ( dp[t1][t2] == c )
{
com.str[c-1] = 'a' + i;
dfs ( t1 - 1, t2 - 1, c-1 );
}
}
}
int main()
{
int i, j, len1, len2;
scanf("%s%s",s1+1, s2+1);
memset(dp,0,sizeof(dp));
memset(pos1,0,sizeof(pos1));
memset(pos2,0,sizeof(pos2));
len1 = strlen(s1+1);
len2 = strlen(s2+1);
for ( i = 1; i <= len1; i++ ) /* 先求出最长子序列的长度 */
{
for ( j = 1; j <= len2; j++ )
{
if ( s1[i] == s2[j] )
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = max ( dp[i-1][j], dp[i][j-1] );
}
}
for ( i = 1; i <= len1; i++ )
{
for ( j = 0; j < 26; j++ )
{
if ( s1[i] == 'a' + j )
pos1[i][j] = i;
else
pos1[i][j] = pos1[i-1][j];
}
}
for ( i = 1; i <= len2; i++ )
{
for ( j = 0; j < 26; j++ )
{
if ( s2[i] == 'a' + j )
pos2[i][j] = i;
else
pos2[i][j] = pos2[i-1][j];
}
}
com.str[dp[len1][len2]] = '\0'; /* 先将子序列的末尾置为 '\0' */
dfs ( len1, len2, dp[len1][len2] );
while ( ! que.empty () )
{
printf("%s\n", que.top().str);
que.pop();
}
return 0;
}