题意:找出一个最大的公共子串,这个子串是一个字符串的尾串(tail substring ),同时是另外那个字符串的头串(head substring),是满足A+B的长度strlen(A+B)达到最小值,这里面要注意的一个问题是,谁做模式串P是不一定的,所以要分别比较不同字符串作为模式的KMP值。
思路:让两个串分别做模式串。看谁KMP的结束的时候匹配的字符字符的个数最多就好。
当然也可以把两个串连接起来再求一次next[len1+len2]即可(求next相当于自我匹配),这时候要注意ans=next[len1+len2]可能大于其中的任何一串,那么就迭代直到(ans=next[ans])<min(len1,len2),因为这个wa了一次
方法一:
//2084 KB 46 ms
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char a[100100],b[100100];
char s1[200200],s2[200200];
int next1[200200],next2[200200];
int combine(char a[],char b[],char s[])
{
bool flag=0;
int len,j;
for(len=0,j=0;;len++,j++){
if(a[j]==0){
if(flag) break;
flag=1;
a=b;
j=0;
}
s[len]=a[j];
}
s[len]=0;
return len;
}
void getnext(char str[],int next[])
{
int i=0;
int j=next[0]=-1;
while(str[i]!=0){
while(j>-1&&str[i]!=str[j])
j=next[j];
i++;
j++;
next[i]=j;
}
}
int kmp(int next[],char fa[],char son[])
{
int i=0,j=0;
int len1=strlen(fa),len2=strlen(son);
while(i<len1&&j<len2){
if(j==-1||fa[i]==son[j]){
j++;
i++;
}
else j=next[j];
}
return fa[i]==0? j:0;
}
int main()
{
while(~scanf("%s%s",a,b)){
getnext(a,next1);
getnext(b,next2);
int cut1=kmp(next2,a,b);
int cut2=kmp(next1,b,a);
if(cut1==cut2){
if(strcmp(a,b)<0) printf("%s%s\n",a,b+cut1);
else printf("%s%s\n",b,a+cut2);
}
else{
if(cut1>cut2) printf("%s%s\n",a,b+cut1);
else printf("%s%s\n",b,a+cut2);
}
}
return 0;
}
贴上大仙的代码:
/*************************************************************************
> File Name: 1867.cpp
> Author: UnknownCUnknown
> Mail: jsnjhcb@icloud.com
> Created Time: 2015年02月12日 星期四 16时17分07秒
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <list>
#include <string>
#include <cstdlib>
#include <queue>
#include <cmath>
#include <climits>
using namespace std;
const int maxn=1e5;
char s1[maxn+10],s2[maxn+10];
char s[2*maxn+10];
int next[2*maxn+10];
int len;
void getNext(){
len=(int)strlen(s);
int j,k;
j=0;k=-1;next[0]=-1;
while(j<len){
if(k==-1||s[j]==s[k]) next[++j]=++k;
else k=next[k];
}
}
char ans[2*maxn+10];
char ans1[2*maxn+10];
int main(){
while(~scanf("%s%s",s1,s2)){
int l1=(int) strlen(s1);
int l2=(int) strlen(s2);
int l=min(l1,l2);
strcpy(s,s2);
strcat(s,s1);
getNext();
int k1=next[len];
while(k1>l){
k1=next[k1];
}
strcpy(s,s1);
strcat(s,s2);
getNext();
int k=next[len];
while(k>l) k=next[k];
if (k>k1){
strcpy(ans,s2);
strcat(ans,s1+k);
}
else if(k<k1){
strcpy(ans,s1);
strcat(ans,s2+k1);
}
else {
strcpy(ans,s2);
strcat(ans,s1+k);
strcpy(ans1,s1);
strcat(ans1,s2+k1);
if(strcmp(ans1,ans)<0){
strcpy(ans,ans1);
}
}
printf("%s\n",ans);
}
return 0;
}