【AC自动机】病毒
【题目链接】
【题意】
寻找一个没有模式串为子串的无限01串。是否存在。
【题解】
其实就是用dfs找一个环。
1、环需要从根结点出发找到这个位置。且重新能走到这里,我们开一个“预测路径”的数组进行标记即可。
2、如果下一个结点碰上了“走过”标记过的,而不是“预测路径”,或者是模式串结尾,我们就避开不走。
注意:
fail数组是可以进行传递的,就是说fail指向的结点,同时是模式串的结尾,那么该位置也是不合法的。
最后看看代码怎么实现就明白了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 7 const int N = 2005; 8 const int M = 30005; 9 10 int Trie[M][2] , fail[M] , End[M], idx ; 11 int Q[M] , Head , Tail ; 12 int vis[M],used[M]; 13 int n ; 14 15 char str[N]; 16 17 void Insert( char s[] ){ 18 int p = 0; 19 for(int i=0 ; s[i] ; i++ ){ 20 int t = s[i] - '0' ; 21 if( !Trie[p][t] ) 22 Trie[p][t] = ++idx ; 23 p = Trie[p][t]; 24 } 25 End[p] ++ ; 26 } 27 28 void Build(){ 29 Head = 1 , Tail = 0 ; 30 for(int i=0;i<2;i++) 31 if(Trie[0][i]) 32 Q[++Tail] = Trie[0][i] ; 33 //fail[Trie[0][i]] = 0; 34 35 while( Head <= Tail ){ 36 int u = Q[Head++] ; 37 for(int i=0;i<2;i++){ 38 int To = Trie[u][i]; 39 if( To ){ 40 fail[To] = Trie[fail[u]][i]; 41 Q[++Tail] = To; 42 43 End[To] = End[To] || End[fail[To]] ; 44 }else{ 45 Trie[u][i] = Trie[fail[u]][i]; 46 } 47 } 48 } 49 50 } 51 52 bool dfs(int u){ 53 vis[u] = 1; 54 for(int i=0;i<=1;i++){ 55 int To = Trie[u][i]; 56 if( vis[To] ) return true; 57 if( used[To] || End[To] ) continue; 58 used[To] = 1 ; 59 if( dfs(To) ) return true ; 60 } 61 vis[u] = 0; 62 return false ; 63 } 64 int main() 65 { 66 scanf("%d",&n); 67 for(int i=0;i<n;i++){ 68 scanf("%s",str); 69 Insert(str); 70 } 71 Build(); 72 puts(dfs(0)?"TAK":"NIE"); 73 74 return 0 ; 75 }