hdu5510(并查集+KMP)

来源:互联网 发布:php开源oa办公系统 编辑:程序博客网 时间:2024/05/16 12:54
/*题解:此题关键在超时,可用并查集来剪枝,把母串的子串都并到母串的集合里这样的目的是查询的时候直接找当前节点的父亲,如果父亲是该串的子串,则子串必定也是,将父亲标记为已经访问,不用再多次重复比较子串;如果父亲不是该串的子串,则直接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;elsereturn -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;}

0 0
原创粉丝点击