/*题解:此题关键在超时,可用并查集来剪枝,把母串的子串都并到母串的集合里 这样的目的是查询的时候直接找当前节点的父亲,如果父亲是该串的子串,则子串 必定也是,将父亲标记为已经访问,不用再多次重复比较子串;如果父亲不是该串 的子串,则直接flag记录该串的下标,该串是满足条件的,最后找出最大下标的该串。 */ //用kmp算法比较一个串是否是另一个串的子串 #include<iostream> #include<cstdio> #include<cstring> using namespace std; char s[502][2002]; const int N=2005; int Next[N]; int fa[2005],vis[2005]; int Find(int x) { return x==fa[x]?x:fa[x]=Find(fa[x]); } void Union(int x,int y) { int f1=Find(x),f2=Find(y); fa[f1]=f2; } void MakeNext(char t[]) { int j,k; j=0,k=-1; Next[0]=-1; int tlen=strlen(t); while(j<tlen) { if(k==-1||t[j]==t[k]) Next[++j]=++k; else k=Next[k]; } } int Kmp_Idx(char s[],char t[]) { int i=0,j=0; MakeNext(t); int slen=strlen(s),tlen=strlen(t); while(i<slen&&j<tlen) { if(j==-1||s[i]==t[j]) { i++;j++; } else j=Next[j]; } if(j==tlen) return i-tlen; else return -1; } int main() { int t; scanf("%d",&t); int cas=0; while(t--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%s",s[i]); int flag=-1; memset(vis,0,sizeof(vis)); for(int i=0;i<=n;i++) fa[i]=i; for(int i=2;i<=n;i++) { memset(vis,0,sizeof(vis)); for(int j=1;j<i;j++) { int fj=Find(j); //cout<<i<<' '<<j<<' '<<fj<<"&"<<endl; if(vis[fj]==1) continue; vis[fj]=1; int tmp=-1; if(strlen(s[i])>=strlen(s[fj])) { tmp=Kmp_Idx(s[i],s[fj]); //cout<<i<<' '<<fj<<' '<<tmp<<'*'<<endl; if(tmp!=-1) Union(fj,i); } if(tmp==-1) { flag=max(flag,i); // cout<<flag<<'*'<<endl; break; } } } printf("Case #%d: %d\n",++cas,flag); } return 0; }
hdu5510(并查集+KMP)
猜你喜欢
转载自blog.csdn.net/zizahn/article/details/52732900
今日推荐
周排行