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 }

浙公网安备 33010602011771号