题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1503
题目大意:给出两个单词,要求凑出一个新单词,并且这个新单词包含前两个单词(存在子序列与前两个单词相同)并且长度最短
关键思想:其实要让长度最短,我们所能省掉的只有1遍LCS,另外的字母都不能省略。LCS,递推方程:当a[i]==b[j]时,dp[i][j]=dp[i-1][j-1]+1(末位相等,那末位一定是LCS元素之一嘛),否则dp[i][j]=max{dp[i-1][j],dp[i][j-1]}.据此得到d数组后,从i,j开始向前走,并处理剩余部分就OK了。
代码如下:
#include <iostream> #include <string> #include <memory.h> using namespace std; const int MAXN=105; int d[MAXN][MAXN];//保存递推方向 int c[MAXN][MAXN];//LCS长度 string ans; void LCS(string a,string b){ memset(d,0,sizeof(d)); for(int i=0;i<=a.size();i++)c[i][0]=0; for(int i=0;i<=b.size();i++)c[0][i]=0; for(int i=1;i<=a.size();i++){ for(int j=1;j<=b.size();j++){ if(a[i-1]==b[j-1]){ c[i][j]=c[i-1][j-1]+1; d[i][j]=0;//0斜 }else{ if(c[i-1][j]>c[i][j-1]){ c[i][j]=c[i-1][j]; d[i][j]=1;//1上 } else{ c[i][j]=c[i][j-1]; d[i][j]=2;//2左 } } } } return; } void output(string a,string b){//根据d数组得到最大公共子序列 int i=a.size(),j=b.size(); ans=""; while(i>0&&j>0){ if(d[i][j]==0){ ans+=a[i-1]; i--,j--; } if(d[i][j]==1){ ans+=a[i-1]; i--; } if(d[i][j]==2){ ans+=b[j-1]; j--; } } while(i>0)ans+=a[i-1],i--; while(j>0)ans+=b[j-1],j--;//处理剩余部分 for(int i=ans.size()-1;i>=0;i--){ cout<<ans[i]; }//逆序输出 cout<<endl; return; } int main(){ string a,b; while(cin>>a>>b){ LCS(a,b); output(a,b); } return 0; }