http://acm.hdu.edu.cn/showproblem.php?pid=1503
解题思路:这道题就是给你两个单词,然后你要把两个单词拼接成一个新单词,使得新单词的子序列中包含两个单词,并且要使这个新单词最短。所以这道题就是求最长公共子序列,并且要记录下子序列的字母,以及他们在主串和副串中的原始位置,之后进行拼接输出。
#include <stdio.h> #include <string.h> #define size 201 int Max(int x,int y) { return x>y?x:y; } struct rem { int i,j;/*i记录主串位置,j记录副串当前字符位置*/ char ch;/*记录当前字符*/ }; char a[size],b[size]; int dp[size][size]; rem ans[size]; int len;/*指示ans的长度*/ void lcs(int m,int n) { int i,j; memset(dp,0,sizeof(dp)); len = 0; for (i=1;i<=m;i++) { for (j=1;j<=n;j++) { if(a[i]==b[j]) dp[i][j] = dp[i-1][j-1]+1; else dp[i][j] = Max(dp[i-1][j],dp[i][j-1]); } } if(dp[m][n] == 0)/*如果没有公共序列,直接输出*/ printf("%s%s",a,b); else { /*取出最长公共子序列的字母*/ i = m,j = n; while (i!=0&&j!=0) { if ((dp[i][j] = dp[i-1][j-1]+1)&&a[i] == b[j]) { ans[len].i = i; ans[len].j = j; ans[len++].ch = a[i];/*倒序保存最长公共子序列字母*/ i--,j--; } else if(dp[i-1][j]>dp[i][j-1]) i--; else j--; } /*取出最长公共子序列的字母*/ } } int main() { int a1,b1,i,j,k; while (scanf("%s%s",a+1,b+1)!=EOF) { a1 = strlen(a+1); b1 = strlen(b+1); lcs(a1,b1); i = j = 1; for (k=len-1;k>=0;k--) { while (i!=ans[k].i) { printf("%c",a[i]); i++; } while (j!=ans[k].j) { printf("%c",b[j]); j++; } printf("%c",ans[k].ch); i++,j++; } printf("%s%s/n",a+ans[0].i+1,b+ans[0].j+1); } return 0; }