Description
A big topic of discussion inside the company is "How should the new creations be called?" A mixture between an apple and a pear could be called an apple-pear, of course, but this doesn't sound very interesting. The boss finally decides to use the shortest string that contains both names of the original fruits as sub-strings as the new name. For instance, "applear" contains "apple" and "pear" (APPLEar and apPlEAR), and there is no shorter string that has the same property.
A combination of a cranberry and a boysenberry would therefore be called a "boysecranberry" or a "craboysenberry", for example.
Your job is to write a program that computes such a shortest name for a combination of two given fruits. Your algorithm should be efficient, otherwise it is unlikely that it will execute in the alloted time for long fruit names.
Input
Input is terminated by end of file.
Output
Sample Input
apple peach ananas banana pear peach
Sample Output
appleach bananas pearch
這道題的對命名的規則本身就描述得不是很清楚,我都是看別人的代碼纔看懂的。代碼大體思路都懂,但是有些細節地方卻一知半解。不過感覺那個倒序存LCS的代碼應該是個模板。
代碼:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<vector>
#include<queue>
#include<stack>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
#define MaxSize 105
#define inf 0x3f3f3f3f
#define LL long long int
int n,m,cnt;
int dp[MaxSize][MaxSize];
char s1[MaxSize],s2[MaxSize];
struct node
{
int i,j;
char c;
} len[MaxSize];
void get_dp()//求出LCS長度
{
n=strlen(s1+1);//注意s1和s2的開始地址,strlen是從給的地址一直掃到'\0',如果這裏寫成了strlen(s1),那麼第一個就是'\0',n就是0了
m=strlen(s2+1);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(s1[i]==s2[j])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
void get_LCS()//儲存LCS裏面的字母
{
int i=n;
int j=m;
cnt=1;
while(i!=0 && j!=0)//倒着去找。這樣能理解,沒問題,但是不知道能不能用正序找。
{
if(s1[i]==s2[j] && dp[i][j] == dp[i-1][j-1]+1)
{
len[cnt].i=i;
len[cnt].j=j;
len[cnt].c=s1[i];
cnt++;
i--;
j--;
}
else if(dp[i-1][j] > dp[i][j-1])//說明i-1之前有和s2[j]一樣的字母,於是i就慢慢退,去找那個字母,那就是第一次讓dp加1的公共字母(感覺上好像是這樣,實際上並沒有想明白)
i--;
else
j--;
}
}
int main()
{
while(~scanf("%s%s",s1+1,s2+1))//從數組的1位置開始,會省去關於dp下標的不少麻煩
{
memset(dp,0,sizeof(dp));
get_dp();
get_LCS();
int i=1;
int j=1;
for(int k=cnt-1;k>=1;k--)
{
while(i!=len[k].i)//將第一串的輸出位置標記慢慢調整到LCS字母之前
{
printf("%c",s1[i]);
i++;
}
while(j!=len[k].j)//將第二串的輸出位置標記慢慢調整到LCS字母之前
{
printf("%c",s2[j]);
j++;
}
printf("%c",len[k].c);//輸出當前的LCS字母
i++;
j++;
}
for(int k=i;k<=n;k++)//把第一串LCS之後的字符串輸出來
printf("%c",s1[k]);
for(int k=j;k<=m;k++)//把第二串LCS之後的字符串輸出來
printf("%c",s2[k]);
printf("\n");
}
return 0;
}//FROM CJZ