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

xiaoxiao2021-02-28  98

公共子序列

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<bits/stdc++.h> 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;i<lenx;i++) { int j; for(j=g;j<leny;j++) if(x[i]==y[j]) break; if(j==leny) continue; dfs(s+1,i+1,j+1); if(s>maxn) maxn=s; } } main() { while(cin>>x>>y) { maxn=0; lenx=x.length(); leny=y.length(); dfs(1,0,0); cout<<maxn<<endl; } }

方法II:动态规划

#include<bits/stdc++.h> 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<bits/stdc++.h> 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<<search(x.length()-1,y.length()-1)<<endl; } }通过这道题我们可以发现,其实记忆化搜索 动态规划的关系就像递归和递推的关系一样,大多数时候可以相互转换。

转载请注明原文地址: https://www.6miu.com/read-28711.html

最新回复(0)