题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1503
题目大意:给你两个字符串, 让你合并两个字符串,每个字符串里的字符相对位置不改变,字符可以共用, 输出最短的目标字符串
思路:先求出最长公共子序列的长度, 再倒序,求出一条最长子字符串,每个字符记录各在s1 和 s2 的位置,然后输出。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdlib> 6 #include <cmath> 7 #include <set> 8 #include <map> 9 #include <vector> 10 using namespace std; 11 12 int max(int a, int b) 13 { 14 return a > b ? a : b; 15 } 16 struct node 17 { 18 int a1, a2; 19 }a[110];//记录s1 和 s2 第 i 个相同字母分别在s1(a1) 和 s2(a2) 的位置 20 int main() 21 { 22 char s1[110], s2[110], s[210]; //s为目标字符串 23 int dp[110][110], i, j;//dp 用来最长公共子序列 24 while(~scanf("%s %s", s1 + 1, s2 + 1)) 25 { 26 strcpy(s, ""); 27 int l1 = strlen(s1 + 1), l2 = strlen(s2 + 1); 28 memset(dp, 0, sizeof(dp)); 29 for(i = 1; i <= l1; i++) 30 { 31 for(j = 1; j <= l2; j++) 32 { 33 dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); 34 if(s2[j] == s1[i]) 35 dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);//求最长公共子序列 36 } 37 } 38 int k = 0, mm = dp[l1][l2], ii = l1 + 1, jj = l2 + 1; 39 for(i = l1; i > 0; i--)//倒序 40 { 41 for(j = l2; j > 0; j--) 42 { 43 if(i < ii && j < jj){//注意, WA 了一发 44 if(s1[i] == s2[j]) { //s1 和 s2 前一个相同的字母i, j 应该分别在此位置i, j 的前面 45 if(dp[i][j] == dp[i - 1][j - 1] + 1 && dp[i][j] == mm) 46 { 47 k++; 48 a[k].a1 = i, a[k].a2 = j; 49 mm--; 50 ii = i, jj = j; 51 } 52 } 53 } 54 if(mm == 0) 55 break; 56 } 57 } 58 i = 1, j = 1; 59 int t = -1; 60 while(k > 0) 61 { 62 while(i < a[k].a1) 63 { 64 s[++t] = s1[i]; 65 i++; 66 67 } 68 while(j < a[k].a2) 69 { 70 s[++t] = s2[j]; 71 j++; 72 } 73 s[++t] = s1[i]; 74 i++, j++; 75 k--; 76 } 77 while(i <= l1){ 78 s[++t] = s1[i]; 79 i++; 80 } 81 while(j <= l2){ 82 s[++t] = s2[j]; 83 j++; 84 } 85 s[++t] = '