LCS记录路径(26个字符以内,重复算一个)

声明:此文转载,方便自己以后分类查看

1)首先按照常规的方法求出最长公共子序列的长度
也就是用O(MN)的那个动态规划,结果放在二维数组dp里
dp[i][j] = { 字串a的1~i部分与字串b的1~j部分的最长公共子序列的长度 }
2)求辅助数组
last1[i][j] = { 到下标i为止,字符j在字串a中最后一次出现的下标 }
last2[i][j] = { 到下标i为止,字符j在字串b中最后一次出现的下标 }
3)枚举最长公共字串的每一个字符
从最后一个字符开始枚举
比如说现在枚举最后一个字符是'C'的情况。
那么 'CDCD' 与 'FUCKC' 这两个字串。
一共有 (0, 2) (0, 4)  (2, 2)  (2. 4) 这四种可能。
很明显前三个是可以舍弃的,因为第四个优于前三个,为后续的枚举提供了更大的空间。
last数组正好是用来做这个的。
4)排序输出
代码里用了stl的set。
注意,由于刚刚的枚举过程是针对每个字符,所以是不用判重的。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cstdio>
 5 #include <queue>
 6 #include <map>
 7 #include <set>
 8 #include <string>
 9 #define frein freopen("D:\\cprogram\\acmprogram\\input", "r", stdin)
10 #define freout freopen("D:\\cprogram\\acmprogram\\ouput", "w", stdout)
11 #define mem(a) memset(a, 0, sizeof(a))
12 #define MAXN 100
13 #define MAXM 100
14 #define INF 1000000000
15 #define MOD 1000000000
16 using namespace std;
17 int dp[MAXM][MAXM];
18 int last1[MAXM][30],last2[MAXM][30];
19 int longest,len1,len2;
20 char s1[MAXM],s2[MAXM];
21 char temp[MAXM];
22 set<string>SET;
23 
24 void find(int end1, int end2, int lens)
25 {
26 //    printf("%d %d %d\n",end1,end2,lens);
27     if(lens==0)
28     {
29         SET.insert(temp+1);
30         return;
31     }
32 
33     for (int i = 0; i < 26; ++i)
34     {
35         int t1 = last1[end1][i];
36         int t2 = last2[end2][i];
37         if(dp[t1][t2]==lens)
38         {
39         //这个地方会把重复的去重,比如abcc abc只算了abcc最后个c,
40         //如果都要输出就外层接2个循环,把所有结尾的都算上;
41             temp[lens]=i+'a';
42             find(t1-1,t2-1,lens-1);
43         }
44     }
45 }
46 
47 void solve()
48 {
49     len1 = strlen(s1+1);
50     len2 = strlen(s2+1);
51     for (int i = 1; i <= len1; ++i)
52         for (int j = 1; j <= len2; ++j)
53         {
54             dp[i][j] = max(dp[i][j-1],dp[i][j]);
55             dp[i][j] = max(dp[i][j],dp[i-1][j]);
56             if(s1[i]==s2[j])
57                 dp[i][j] = dp[i-1][j-1]+1;
58         }
59     longest = dp[len1][len2];
60     //    printf("%d\n", longest);LCS结果
61 
62     //这里要保证last数组里边都是0;
63         
64     for (int i = 1; i <= len1; ++i)
65         for (int j = 0; j < 26; ++j)
66         {
67             if(s1[i]==j+'a')
68                 last1[i][j] = i;
69             else
70             last1[i][j] = last1[i-1][j];
71         }
72 
73     for (int i = 1; i <= len2; ++i)
74         for (int j = 0; j < 26; ++j)
75         {
76             if(s2[i]==j+'a')
77                 last2[i][j] = i;
78             else
79             last2[i][j] = last2[i-1][j];
80         }
81 //        printf("%d %d\n",last1[4][2],last1[3][2]);
82         temp[longest+1]='\0';
83         find(len1,len2,longest);
84         set<string>::iterator it;
85         for(it=SET.begin();it!=SET.end();it++)
86             printf("%s\n",(*it).c_str());
87 }
88 int main(int argc, char const *argv[])
89 {
90     scanf("%s%s",s1+1,s2+1);
91     solve();
92     return 0;
93 }

 

posted @ 2018-10-21 11:50  osatalp  阅读(351)  评论(0)    收藏  举报