洛谷 P2444 [ POI 2000 ] 病毒 —— AC自动机+dfs

题目:https://www.luogu.org/problemnew/show/P2444

AC自动机上 dfs,不走结尾点,如果走出环就是有无限长度的串;

RE无数,原来是数组开成 2000 的了...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=2005,xm=30005;
int n,cnt,c[xm][2],fail[xm];
bool vis[xm],end[xm],in[xm];
char dc[xm];
queue<int>q;
void build()
{
  int nw=0,l=strlen(dc);
  for(int i=0;i<l;i++)
    {
      int t=dc[i]-'0';
      if(!c[nw][t])c[nw][t]=++cnt; nw=c[nw][t];
    }
  end[nw]=1;
}
void getfail()
{
  for(int i=0;i<=1;i++)
    if(c[0][i])fail[c[0][i]]=0,q.push(c[0][i]);
  while(q.size())
    {
      int x=q.front(); q.pop();
      end[x]|=end[fail[x]];
      for(int i=0;i<=1;i++)
        {
          if(c[x][i])fail[c[x][i]]=c[fail[x]][i],q.push(c[x][i]);
          else c[x][i]=c[fail[x]][i];
        }
    }
}
bool dfs(int x)
{
  vis[x]=1; in[x]=1;
  for(int i=0;i<=1;i++)
    {
      if(!c[x][i]||end[c[x][i]])continue;//也可没有 !c[x][i] 
      if(in[c[x][i]])return 1;//注意在判断 vis 之前 
      if(vis[c[x][i]])continue;//!return 0!
      vis[c[x][i]]=1;
      if(dfs(c[x][i]))return 1;//
    }
  in[x]=0;
  return 0;
}
int main()
{
  scanf("%d",&n);
  for(int i=1;i<=n;i++)scanf("%s",dc),build();
  getfail();
  if(dfs(0))printf("TAK\n");
  else printf("NIE\n");
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9763308.html