博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 【POJ1934】 Trip

题目意思:

有两个字符串(长度\(<=80\)),按字典序输出它们的最长公共子串的所有情况.

解析

最长公共子序列的长度应该都没问题了吧...有问题请自行百度

但关键是要求出每种情况,还要按字典序...

考虑到长度\(<=80\),我们可以用搜索+剪枝,

设两个串为\(a\),\(b\),长度为\(la\),\(lb\),

\(f[i][j]\)表示\(a\)串中的\(1\)~\(i\)\(b\)串中的$ 1\(~\)j$的最长公共子序列的长度.

先求出最长公共子序列的长度\(len\)=\(f[la][lb]\),

那么.我们就是要求出一个长度为\(len\)\(a\),\(b\),的子串,

我们再设\(f1[i][j]\)表示在\(a\)串的\(1\)~\(j\)中,字母\(i\)出现的最后一个位置,

\(f2[i][j]\)就表示\(b\)串,其中\(i\)\(1\)~\(26\),

那么在搜索时,记录\(4\)个信息:\(a\)串还能取的长度\(l1\),\(b\)串还能取的长度\(l2\),当前求出的子串\(s\)和还需要求的子串的长度\(l\).

那么,在一开始时,状态就应该是(\(la,lb,"",len\)),其中\(s\)是一个空串.

那么,在搜索时枚举每个字母\(ci\),设\(p1\)表示\(f1[ci][l1]\),\(p2\)表示\(f2[ci][l2]\),

那么,若\(f[p1][p2]>=l\),即最终能形成长度为\(len\)的子串,就将\(ci\)加入\(s\),

并且注意,由于我们是倒着搜的,所以要用\(ci+s\)而不是\(s+ci\).

\(l1\)\(l2\)小于\(0\)时,即搜不到了,就返回,

而当\(l\)等于\(0\)时就添加答案并返回.

最后排序后输出就行了.

具体实现看代码吧:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;

inline int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
	return f*sum;
}

int f[101][101],tot=0;
char a[101],b[101];
int f1[27][101],f2[27][101];
string ans[1001];

void find(int l1,int l2,string s,int l){
	if(l1<0||l2<0) return ;
	if(l<=0){ans[++tot]=s;return ;}
	for(int i=1;i<=26;i++){
		int p1=f1[i][l1],p2=f2[i][l2];
		if(f[p1][p2]!=l) continue;
		char c=i+96;
		find(p1-1,p2-1,c+s,l-1);
	}
}

int main(){
	cin>>a>>b;
	int la=strlen(a),lb=strlen(b);
	for(int i=la;i;i--) a[i]=a[i-1];
	for(int i=lb;i;i--) b[i]=b[i-1];//这两步是整体位移,个人习惯而已
	for(int i=1;i<=26;i++){
		for(int j=1;j<=la;j++){
			if(a[j]==i+96) f1[i][j]=j;
			else f1[i][j]=f1[i][j-1];
		}
		for(int j=1;j<=lb;j++){
			if(b[j]==i+96) f2[i][j]=j;
			else f2[i][j]=f2[i][j-1];
		}
	}//记录f1,f2
	for(int i=1;i<=la;i++){
		for(int j=1;j<=lb;j++){
			f[i][j]=max(f[i-1][j],f[i][j-1]);
			if(a[i]==b[j]) f[i][j]=max(f[i-1][j-1]+1,f[i][j]);
		}
	}//寻找最长公共子序列
	find(la,lb,"",f[la][lb]);
	sort(ans+1,ans+tot+1);
	for(int i=1;i<=tot;i++) cout<<ans[i]<<endl;
	return 0;
}

posted @ 2019-04-02 18:02  Hastin  阅读(208)  评论(0编辑  收藏  举报