POJ 1934 Trip【最长公共子序列输出】

Description

Alice and Bob want to go on holiday. Each of them has planned a route, which is a list of cities to be visited in a given order. A route may contain a city more than once. 
As they want to travel together, they have to agree on a common route. None wants to change the order of the cities on his or her route or add other cities. Therefore they have no choice but to remove some cities from the route. Of course the common route should be as long as possible. 
There are exactly 26 cities in the region. Therefore they are encoded on the lists as lower case letters from 'a' to 'z'.

Input

The input consists of two lines; the first line is Alice's list, the second line is Bob's list. 
Each list consists of 1 to 80 lower case letters with no spaces inbetween.

Output

The output should contain all routes that meet the conditions described above, but no route should be listed more than once. Each route should be printed on a separate line. There is at least one such non-empty route, but never more than 1000 different ones. Output them in ascending order.

Sample Input

abcabcaa
acbacba

Sample Output

ababa
abaca
abcba
acaba
acaca
acbaa
acbca

思路:看到一大牛的博客这样写道:

1)首先按照常规的方法求出最长公共子序列的长度
也就是用O(MN)的那个动态规划,结果放在二维数组dp
dp[i][j] = {
字串a的1~i部分与字串b的1~j部分的最长公共子序列的长度 }
2
)求辅助数组
last1[i][j] = {
到下标i为止,字符j在字串a中最后一次出现的下标 }
last2[i][j] = {
到下标i为止,字符j在字串b中最后一次出现的下标 }
3
)枚举最长公共字串的每一个字符
从最后一个字符开始枚举
比如说现在枚举最后一个字符是'C'的情况。
那么 'CDCD' 与 'FUCKC' 这两个字串。
一共有 (0, 2) (0, 4) (2, 2) (2. 4) 这四种可能。
很明显前三个是可以舍弃的,因为第四个优于前三个,为后续的枚举提供了更大的空间。
last
数组正好是用来做这个的。
4
)排序输出
代码里用了stl的set
注意,由于刚刚的枚举过程是针对每个字符,所以是不用判重的。
代码如下:

#include<stdio.h>
#include<set> 
#include<string.h>
#include<iostream>
#include<algorithm>
#include<string> 
using namespace std;
int dp[105][105];
char ch1[105], ch2[105], temp[105];
int last1[105][27], last2[105][27]; 
set<string>SET;
void find(int x, int y, int len)
{
	int i, j; 
	if(len<=0)
	{
		SET.insert(&temp[1]);
		return ;
	}
	if(x>0&&y>0)
	{
		for(i=0; i<26; i++)
		{
			int t1=last1[x][i];
			int t2=last2[y][i];
			if(dp[t1][t2]==len)
			{
				temp[len]='a'+i;
				find(t1-1, t2-1, len-1);
			}
		}
	}
}	 
int main()
{
	int i, j, len1, len2;
	while(scanf("%s %s", &ch1[1], &ch2[1])!=EOF)
	{
		memset(last1, 0, sizeof(last1));
		memset(last2, 0, sizeof(last2));
		memset(dp, 0, sizeof(dp));
		len1=strlen(&ch1[1]);
		len2=strlen(&ch2[1]);
		for(i=1; i<=len1; i++)
			for(j=1; j<=len2; j++)
			{
				if(ch1[i]==ch2[j])
					dp[i][j]=dp[i-1][j-1]+1;
				else
					dp[i][j]=max(dp[i][j-1], dp[i-1][j]);
			}
		for(i=1; i<=len1; i++)
			for(j=0; j<26; j++)
			{
				if(ch1[i]=='a'+j)
					last1[i][j]=i;
				else
					last1[i][j]=last1[i-1][j];
			}
		for(i=1; i<=len2; i++)
			for(j=0; j<26; j++)
			{
				if(ch2[i]=='a'+j)
					last2[i][j]=i;
				else
					last2[i][j]=last2[i-1][j];
			}
		temp[dp[len1][len2]+1]='\0'; 
 	 	find(len1, len2, dp[len1][len2]);
		set<string>::iterator it;
        for(it=SET.begin();it!=SET.end();it++)
        {
            printf("%s\n",(*it).c_str());
        }
	}
	return 0;
}	   

 

转载于:https://www.cnblogs.com/Hilda/archive/2012/07/31/2616862.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值