病毒

https://loj.ac/problem/10062

题目描述

  给出n个字符串,求是否存在一个无限长度的字符串使这n个字符串都不是它的子串。

思路

  当你想到这道题可能与Trie图有关,你就成功一半了。我们考虑在Trie图上如何求解答案,首先如果说存在这样一个无限长的子串,那么显然在Trie图上形成了一条环,并且这条环不经过每个串的结尾,而且这个环一定能从根节点开始访问。对于求环我们可以用dfs,即用两个数组vis和v,vis表示是否访问过,v表示这个节点是否在搜索的栈中,如果由环直接输出即可。

代码

#include<bits/stdc++.h>
using namespace std;

int ch[30010][2],tot=1;
bool ed[30010];
void insert(char *s)
{
    int u=1,len=strlen(s);
    for(int i=0;i<len;i++)
    {
        int c=s[i]-'0';
        if(!ch[u][c])ch[u][c]=++tot;
        u=ch[u][c];
    }
    ed[u]=1;
}
int nxt[30010];
void getfail()
{
    for(int i=0;i<=1;i++)
        ch[0][i]=1;
    queue<int>q;
    q.push(1);nxt[1]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<=1;i++)
        {
            if(!ch[u][i])ch[u][i]=ch[nxt[u]][i];
            else
            {
                int v=nxt[u];
                q.push(ch[u][i]);
                while(v&&!ch[v][i])v=nxt[v];
                nxt[ch[u][i]]=ch[v][i];
            }
        }
    }
    for(int i=1;i<=tot;i++)
    {
        int v=nxt[i];
        while(v)ed[i]|=ed[v],v=nxt[v];
    }
}
bool vis[30010],v[30010];
void dfs(int u)
{
    vis[u]=1;v[u]=1;
    for(int i=0;i<=1;i++)
    {
        if(v[ch[u][i]])
        {
            printf("TAK");
            exit(0);
        }
        else if(!ed[ch[u][i]]&&!vis[ch[u][i]])
            dfs(ch[u][i]);
    }
    v[u]=0;
}

char s[30010];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf(" %s",s);
        insert(s);
    } 
    getfail();
//    for(int i=1;i<=tot;i++)
//        cout<<i<<' '<<nxt[i]<<endl;
    dfs(0);
    printf("NIE"); 
} 

猜你喜欢

转载自www.cnblogs.com/fangbozhen/p/11647520.html