1. 程式人生 > >2938. [POI2000]病毒【AC自動機】

2938. [POI2000]病毒【AC自動機】

color esc mar hellip tex dash sample script 需要

Description

二進制病毒審查委員會最近發現了如下的規律:某些確定的二進制串是病毒的代碼。如果某段代碼中不存在任何一段病毒代碼,那麽我們就稱這段代碼是安全的。現在委員會已經找出了所有的病毒代碼段,試問,是否存在一個無限長的安全的二進制代碼。 示例: 例如如果{011, 11, 00000}為病毒代碼段,那麽一個可能的無限長安全代碼就是010101…。如果{01, 11, 000000}為病毒代碼段,那麽就不存在一個無限長的安全代碼。 任務: 請寫一個程序: l 讀入病毒代碼; l 判斷是否存在一個無限長的安全代碼; l 將結果輸出

Input

第一行包括一個整數n,表示病毒代碼段的數目。以下的n行每一行都包括一個非空的01字符串——就是一個病毒代碼段。所有病毒代碼段的總長度不超過30000。

Output

你應在在文本文件WIN.OUT的第一行輸出一個單詞: l TAK——假如存在這樣的代碼; l NIE——如果不存在。

Sample Input

3
01
11
00000

Sample Output

NIE

QvQ現在才理解AC自動機buildfail的時候繼承兒子其實就相當於他的兒子就是fail指針

對於這個題只需要建好trie樹,然後在trie樹上找一個環
為什麽呢?因為我們如果拿一個安全代碼在自動機上跑
一定會不停的跑而到不了單詞的結束點,這就要求必須有個環
而且這個環要求必須經過根節點,且不經過一些限制節點
限制節點包括單詞的結束節點,還有若一個點的fail指向的點是限制節點
那麽這個點也是限制節點。
因為fail指向的是當前串的最長後綴,
fail指向的後綴都是病毒了,那當前串本身一定也是病毒了

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5
#define N (100000+100) 6 using namespace std; 7 int Son[N][27],Fail[N],End[N],Ind[N]; 8 int n,sz,head[N],num_edge; 9 bool vis[N],flag; 10 char s[N]; 11 queue<int>q; 12 13 void Insert(char s[]) 14 { 15 int now=0,len=strlen(s); 16 for (int i=0; i<len; ++i) 17 { 18 int x=s[i]-0; 19 if (!Son[now][x]) Son[now][x]=++sz; 20 now=Son[now][x]; 21 } 22 ++End[now]; 23 } 24 25 void Build_Fail() 26 { 27 for (int i=0; i<=1; ++i) 28 if (Son[0][i]) 29 q.push(Son[0][i]); 30 while (!q.empty()) 31 { 32 int now=q.front(); 33 q.pop(); 34 for (int i=0; i<=1; ++i) 35 { 36 if (!Son[now][i]) 37 { 38 Son[now][i]=Son[Fail[now]][i]; 39 continue; 40 } 41 Fail[Son[now][i]]=Son[Fail[now]][i]; 42 if (End[Fail[Son[now][i]]]) End[Son[now][i]]++; 43 //因為fail指針指向的點代表的字符串一定是當前字符串的一個最長後綴 44 //若後綴都是病毒了,那他本身一定也是病毒了 45 q.push(Son[now][i]); 46 } 47 } 48 } 49 50 int ins[N],used[N]; 51 bool Dfs(int x) 52 { 53 ins[x]=1; 54 for(int i=0; i<2; i++) 55 { 56 int v=Son[x][i]; 57 if(ins[v])return 1; 58 if(used[v]||End[v])continue; 59 used[v]=1; 60 if(Dfs(v))return 1; 61 } 62 ins[x]=0; 63 return 0; 64 } 65 66 int main() 67 { 68 scanf("%d",&n); 69 for (int i=1; i<=n; ++i) 70 scanf("%s",s),Insert(s); 71 Build_Fail(); 72 if(Dfs(0))puts("TAK"); 73 else puts("NIE"); 74 }

2938. [POI2000]病毒【AC自動機】