POJ 3450 Corporate Identity (KMP,求公共子串,方法很妙)
http://blog.sina.com.cn/s/blog_74e20d8901010pwp.html
我采用的是方法三。
注意:当长度相同时,取字典序最小的。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> /* http://blog.sina.com.cn/s/blog_74e20d8901010pwp.html 我采用的是方法三。 注意:当长度相同时,取字典序最小的。 */ using namespace std; const int maxn=4005; char str[maxn][210]; int n; int minlen; //n个字符串中最短的长度 int id; //长度最短字符串的编号 int next[210]; void getNext(char*P){ int k; int lm=strlen(P); next[1]=0; k=0; for(int i=1;i<lm;i++){ while(k>0 && P[k]!=P[i]) k=next[k]; if(P[k]==P[i]) k++; next[i+1]=k; } } int kmp(char*T,char*P){ int k,c; c=0; //表示字符串P在T中能够匹配的最大长度 int ln=strlen(T),lm=strlen(P); for(int i=0;i<ln;i++){ while(k>0&&P[k]!=T[i]) k=next[k]; if(P[k]==T[i]) k++; if(k>c) c=k; if(k==lm) return k; } return c; } int main() { int l; while(scanf("%d",&n)!=EOF){ if(n==0) break; minlen=1000; for(int i=1;i<=n;i++){ scanf("%s",str[i]); l=strlen(str[i]); if(l<minlen){ minlen=l; id=i; } } char tmp[210],s[210]; int minl,maxl=0,cnt; //minl为枚举的后缀在其余n-1个字符串中都能匹配的长度 //maxl为公共子串的最大长度 char ans[210]; //所求公共子串 for(int i=1;i<=minlen;i++){ strncpy(tmp,str[id]+minlen-i,i); tmp[i]='\0'; getNext(tmp); minl=i+1; for(int j=1;j<=n;j++){ if(j!=id){ cnt=kmp(str[j],tmp); minl=min(cnt,minl); } } if(minl>maxl){ maxl=minl; strncpy(ans,tmp,minl); ans[minl]='\0'; } //如果相等长度,则输出字典序最小的 else if(minl==maxl){ strncpy(s,tmp,minl); s[minl]='\0'; if(strcmp(s,ans)<0) strcpy(ans,s); } } if(maxl==0) printf("IDENTITY LOST\n"); else printf("%s\n",ans); } return 0; }