C++记忆化搜索算法与动态规划算法之公共子序列

公共子序列

Description

我们称序列Z = < z1, z2, ..., zk >是序列X = < x1, x2, ..., xm >的子序列当且仅当存在 严格上升 的序列< i1, i2, ..., ik >,使得对j = 1, 2, ... ,k, 有xij = zj。比如Z = < a, b, f, c > 是X = < a, b, c, f, b, c >的子序列。

现在给出两个序列X和Y,你的任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列。

Input

输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列。两个字符串之间由若干个空格隔开。

Output

对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。

Sample Input

abcfbc         abfcab
programming    contest 
abcd           mnp

Sample Output

4
2
0

解题

看到这道题的时候,我发现这道题可以用3种方案,分别是深搜(TLE)、动态规划(AC)、记忆化搜索(AC)。

方法I:深搜

#include
using namespace std;
string x,y;
int lenx,leny,maxn;
void dfs(int s,int t,int g)
{
	if(t>=lenx||g>=leny) return ;
	for(int i=t;imaxn) maxn=s;
	}
}
main()
{
	while(cin>>x>>y)
	{
		maxn=0;
		lenx=x.length();
		leny=y.length();
		dfs(1,0,0);
		cout<

方法II:动态规划



#include
using namespace std;
int ans,A[201][201],lenx,leny,flag[201][201];
string x,y;
void DP()  
{
    memset(A,0,sizeof(A));
    for(int i=1;i<=lenx;++i)  
		flag[i][0]=1; 
    for(int i=1;i<=leny;++i)  
        flag[0][i]=-1;
    for(int i=1;i<=lenx;++i)  
        for(int j=1;j<=leny;++j)  
        {
            if(x[i-1]==y[j-1]) 
            {
                A[i][j]=A[i-1][j-1]+1;
                flag[i][j]=0;
            }
            else if(A[i-1][j]>=A[i][j-1])  
            {
                A[i][j]=A[i-1][j];
                flag[i][j]=1;
            }
            else
            {
                A[i][j]=A[i][j-1];
                flag[i][j]=-1;
            }
        }
}
void print(int x,int y)  
{
    if(!x&&!y)
        return ;
    if(flag[x][y]==0)  
    {
        print(x-1,y-1);
        ans++;
    }
    else if(flag[x][y]==1)  
        print(x-1,y);
    else 
        print(x,y-1);
}
int main()  
{
    while(cin>>x>>y)  
    {
		ans=0;
        lenx=x.size();
        leny=y.size();
        DP();
        print(lenx,leny);
        printf("%d\n",ans);
    }
} 

方法III:记忆化搜索


#include
using namespace std;
string x,y;
int lenx,leny,A[201][201];
int search(int i,int j)
{
	if(A[i][j]+1) return A[i][j];
	if(!i&&!j)
	{
		if(x[i]==y[j])
			return A[i][j]=1;
		else
			return A[i][j]=0;
	}
	if(!i)
	{
		for(int k=j;k>=0;k--)
			if(x[i]==y[k])
				return A[i][j]=1;
		return A[i][j]=0;
	}
	if(!j)
	{
		for(int k=i;k>=0;k--)
			if(x[k]==y[j])
				return A[i][j]=1;
		return A[i][j]=0;
	}
	if(x[i]==y[j]) return A[i][j]=1+search(i-1,j-1);
	else return A[i][j]=max(search(i,j-1),search(i-1,j));
}
int main()
{
	while(cin>>x>>y)
	{
		memset(A,-1,sizeof(A));
		cout<
通过这道题我们可以发现,其实记忆化搜索 动态规划的关系就像递归和递推的关系一样,大多数时候可以相互转换。

你可能感兴趣的:(记忆化搜索,动态规划,动态规划刷题集锦,搜索算法刷题集锦,错题大总结,C++学习日志)