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 }

 

posted @ 2018-08-30 12:51  RedBlack  阅读(482)  评论(0编辑  收藏  举报