LCS问题

概念明晰:

- longest common sub-sequences:最长 - 公共 - 子 - 序列

  • 子串:按原顺序依次出现,禁止跳过某元素
  • 子序列:在保持元素前后关系的前提下,可以跳过某些元素的序列

例题:Common Subsequence(HDU 1159)

解题思路:

  • 动态规划:
    一般来说,动态规划分为五个部分:
    1.状态转移方程
    2.表格的初始化
    3.确定循环顺序
    4.复杂度的优化
    5.记录抉择路径

优化过程:

  • 对于dp问题,最快的优化方法是手推表格。表格能提供两个信息:dp[i][j]需要用到哪些格子,如何去用这些格子
  • 用到哪些”告诉我们需要保存几维信息,“如何去用”告诉我们方程的形式。比如本题的空间优化方法,不手推表格是很难想到的。

代码:

  • 状态转移方程:
if(s[i] == t[j])	
	lcs[i][j] = lcs[i-1][j-1] + 1;
else
	lcs[i][j] = max(lcs[i][j-1] , lcs[i-1][j]);
  • 完整代码1(原始正方形dp:124MS 5356K)
//原始正方形dp:124MS		5356K


#include 
#include 
#include 
#include 

using namespace std;
const int maxn = 1005;

string s,t;
int lcs[maxn][maxn];//lcs[i][j]代表两前缀s[1...i] & t[1...j]的LCS 

int GetLCS(){
	int nums = s.length();
	int numt = t.length();
	int i=1 , j=1;
	string::iterator sp,tp;
	memset(lcs,0,sizeof(lcs));
	for(sp = s.begin() ; sp != s.end() ; i++,sp++){
		j=1; 
		for(tp = t.begin() ; tp != t.end() ; j++,tp++){
			if(*sp == *tp)
				lcs[i][j] = lcs[i-1][j-1] + 1;
			else
				lcs[i][j] = max(lcs[i][j-1] , lcs[i-1][j]);
		}
	}
	return lcs[nums][numt];
}

int main(){
	while(cin>>s>>t){
		int ans = GetLCS();
		cout<<ans<<endl;
	}
	return 0;
}
  • 完整代码2(一维dp:46MS 1408K)
//一维dp:46MS		1408K


#include 
#include 
#include 
#include 

using namespace std;
const int maxn = 1005;
string s,t;
int lcs[maxn];
int rec[maxn];//record[i]记录需要用到的上一维的信息

int main(){
	while(cin>>s>>t){
		string::iterator sp , tp;
		int i,j;
		memset(lcs , 0 , sizeof(lcs));
		memset(rec , 0 , sizeof(rec));
		for(sp = s.begin(),i = 1 ; sp != s.end() ; sp++,i++){
			for(tp = t.begin(),j = 1 ; tp != t.end() ; tp++,j++){
				if(*sp == *tp)
					lcs[j] = rec[j-1] + 1;
				else
					lcs[j] = max(rec[j] , lcs[j-1]);
			}
			if(sp+1 == s.end()) break;
			while(j--)
				rec[j] = lcs[j];
		}
		cout<<lcs[j-1]<<endl;
	}
	return 0;
}

你可能感兴趣的:(ACM,动态规划,杂文讲解)