51nod1006最长公共子序列(lcs输出路径)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1006
分析和思路:
理解dp数组存的含义,dp[i][j]代表前i个字符和前j个字符的最长lcs数,dp方程:
dp[i][j]=dp[i-1][j-1]+1 a[i]==b[j]
dp[i][j]=max(dp[i][j-1], dp[i-1][j]) a[i]!=b[j]
如果a[i]=b[j],那么很明显dp[i][j]=dp[i-1][j-1]+1;
若a[i]!=b[j],我们假设a, b的最大匹配串为c,显然a[i], b[j]不能同时作为c的最后一个字符,那么最优匹配情况即为a[i]为c的最后一个字符或者b[j]为c的最后一个字符(这点不大好理解),即:
dp[i][j]=dp[i][j-1] a[i]是c的最后一个字符即匹配的末尾字符
dp[i][j]=dp[i-1][j] b[j]是c的最后一个字符即匹配的末尾字符 (其实当a[i], b[j]都不是c的最后一个字符时即a[i], b[j]都不匹配时dp[i][j]=dp[i-1][j-1])
不等于时即可简写为一个式子dp[i][j]=max(dp[i][j-1], dp[i-1][j])
输出路径,倒着取出再倒着输出,将正向dp过程搞清楚倒过来理解即可。
理解好dp代表的含义和搞清楚dp的过程是关键。
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 using namespace std; 5 const int maxn=1005; 6 string s1,s2; 7 char a[maxn]; 8 int p=1,dp[maxn][maxn]; 9 10 11 void getlen(int len1,int len2) 12 { 13 for(int i=1;i<=len1;i++) 14 { 15 for(int j=1;j<=len2;j++) 16 { 17 if(s1[i]==s2[j]) 18 { 19 dp[i][j]=dp[i-1][j-1]+1; 20 } 21 else if(dp[i-1][j]>=dp[i][j-1]) 22 { 23 dp[i][j]=dp[i-1][j]; 24 } 25 else 26 { 27 dp[i][j]=dp[i][j-1]; 28 } 29 } 30 } 31 } 32 33 void getlcs(int i,int j) 34 { 35 while(i>=1 && j>=1) 36 { 37 if(s1[i]==s2[j]) 38 { 39 a[p++]=s1[i]; 40 i--; 41 j--; 42 } 43 else if(dp[i-1][j]<=dp[i][j-1])//关键:说明之前的最长lcs是在s1[0,i]和s2[0,j-1]中!i本身是一员!不能少! 44 { 45 j--; 46 } 47 else//同理上 48 { 49 i--; 50 } 51 } 52 } 53 54 int main() 55 { 56 cin>>s1>>s2; 57 58 int len1=s1.length(),len2=s2.length(); 59 for(int i=len1;i>=1;i--) s1[i]=s1[i-1];//后移方便 60 for(int i=len2;i>=1;i--) s2[i]=s2[i-1]; 61 62 getlen(len1,len2); 63 getlcs(len1,len2); 64 for(int i=p-1;i>=1;i--) cout<<a[i]; 65 cout<<endl; 66 67 return 0; 68 }
51nod1183编辑距离,与lcs相似的题,只不过想的角度,dp代表含义不一样
s1[i]==s2[j]时,不用操作,不等时+1,因为不管是增加还是替换都一样操作一步
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int maxn=1005; 7 int dp[maxn][maxn]; 8 string s1,s2; 9 10 void solve(int len1,int len2) 11 { 12 for(int i=1;i<=len1;i++) 13 { 14 for(int j=1;j<=len2;j++) 15 { 16 if(s1[i]==s2[j])//相同不用操作,不同增加一个操作 17 { 18 dp[i][j]=dp[i-1][j-1]; 19 } 20 else 21 { 22 dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;//dp[i-1][j-1]举个例子就明白 23 } //ab,akscb dp[2][2]=dp[1][1]+1=1; 24 } 25 } 26 } 27 28 int main() 29 { 30 ios::sync)with_stdio(false); cin.tie(0); 31 32 cin>>s1>>s2; 33 34 int len1=s1.length(),len2=s2.length(); 35 for(int i=len1;i>=1;i--) s1[i]=s1[i-1]; 36 for(int i=len2;i>=1;i--) s2[i]=s2[i-1]; 37 for(int i=0;i<=(len1>len2?len1:len2);i++) dp[i][0]=i; 38 for(int i=0;i<=(len1>len2?len1:len2);i++) dp[0][i]=i; 39 40 solve(len1,len2); 41 cout<<dp[len1][len2]<<endl; 42 43 return 0; 44 }
完