欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

最长公共子序列(LCS)模板

程序员文章站 2024-01-14 14:22:22
...

HDU-1503

#include<bits/stdc++.h>
using namespace std;
int dp[105][105];

int main(){
	string s1,s2;
	while(cin>>s1>>s2){
		memset(dp,0,sizeof(dp));
		
		//构成dp表 
		for(int i=1;i<=s1.length();i++){
			for(int j=1;j<=s2.length();j++){
				if(s1[i-1]==s2[j-1]){
					dp[i][j]=dp[i-1][j-1]+1;
				}
				else {
					dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
				}
			}
		}
		
		//根据dp表寻找某一个最长子序列 
		stack<char> LCS;
		for(int i=s1.length(),j=s2.length();j>=1&&i>=1;){
			if(s1[i-1]==s2[j-1]){
				LCS.push(s1[i-1]);
				--i;--j;
			}
			else {//不相等时分类讨论
				if(dp[i-1][j]==dp[i][j-1]){//统一选定一种方向 向左或向上 
					--j;
					continue;
				}
				if(dp[i-1][j]==dp[i][j]){//如果是从dp[i-1][j]拓展出的dp[i][pj 
					--i;//向上移动一格 
				}
				else {
					--j;//向左移动一格 
				}
			}
		}
		
		/*
		while(!LCS.empty()){
			char c=LCS.top();
			LCS.pop();
			cout<<c;
		}
		cout<<endl;
		*/
		
		int p1,p2;
		p1=p2=0;
		while(!LCS.empty()){
			char c=LCS.top();
			
			while(p1<s1.length()&&s1[p1]!=c){
				printf("%c",s1[p1]);
				p1++;
			}
			while(p2<s2.length()&&s2[p2]!=c){
				printf("%c",s2[p2]);
				p2++;
			}
			
			printf("%c",c);
			LCS.pop();
			p1++;p2++;
		}
		while(p1<s1.length()){
			printf("%c",s1[p1]);
			p1++;
		}
		while(p2<s2.length()){
			printf("%c",s2[p2]);
			p2++;
		}
		cout<<endl;
		
	}
	return 0;
}

没正式学习LCS前想当然的认为加维存储序列s1前i个字符与s2前j个字符能过,实际上后面的状态会覆盖掉前面已经存好的。

正解如上需要利用回溯的方法回推某个最长子序列。

错误代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
char dp[105][105][105];

int main(){
	string s1,s2;
	while(cin>>s1>>s2){
		memset(dp,0,sizeof(dp));
		s1+='_';
		s2+='+';
		
		int l1,l2;
		l1=s1.length();
		l2=s2.length();
		int l=0;
		for(int i=1;i<=l1;i++){
			for(int j=1;j<=l2;j++){
				int k=0;
				while(dp[i-1][j-1][++k]!=0){
					dp[i][j-1][k]=dp[i-1][j-1][k];
					dp[i-1][j][k]=dp[i-1][j-1][k];
					dp[i][j][k]=dp[i-1][j-1][k];
				}
				if(s1[i-1]==s2[j-1]){
					dp[i][j][k]=s1[i-1];
					l=k;
				}
			}
		}
		
		int p1,p2;
		p1=p2=0;
		for(int i=1;i<=l;i++){//l为lcs长度 
			while(p1<l1-1&&s1[p1]!=dp[l1-1][l2-1][i]){
				printf("%c",s1[p1]);
				p1++;
			}
			while(p2<l2-1&&s2[p2]!=dp[l1-1][l2-1][i]){
				printf("%c",s2[p2]);
				p2++;
			}
			printf("%c",dp[l1-1][l2-1][i]);
			p1++;p2++;
		}
		while(p1<l1-1){
			printf("%c",s1[p1]);
			p1++;
		}
		while(p2<l2-1){
			printf("%c",s2[p2]);
			p2++;
		}
		cout<<endl;
	}
	return 0;
}

/*
appleananas bananapeach
cranberry boysenberry
nberry boysenberry
*/