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");
}