1. 程式人生 > >洛谷P2444 病毒【AC自動機】

洛谷P2444 病毒【AC自動機】

long 字符 結果 程序 沒有 int pan 描述 恢復

題目描述

二進制病毒審查委員會最近發現了如下的規律:某些確定的二進制串是病毒的代碼。如果某段代碼中不存在任何一段病毒代碼,那麽我們就稱這段代碼是安全的。現在委員會已經找出了所有的病毒代碼段,試問,是否存在一個無限長的安全的二進制代碼。

示例:

例如如果{011, 11, 00000}為病毒代碼段,那麽一個可能的無限長安全代碼就是010101…。如果{01, 11, 000000}為病毒代碼段,那麽就不存在一個無限長的安全代碼。

任務:

請寫一個程序:

1.在文本文件WIR.IN中讀入病毒代碼;

?2.判斷是否存在一個無限長的安全代碼;

?3.將結果輸出到文件WIR.OUT中。

輸入輸出格式

輸入格式:

在文本文件WIR.IN的第一行包括一個整數n(n\le 2000)(n2000),表示病毒代碼段的數目。以下的n行每一行都包括一個非空的01字符串——就是一個病毒代碼段。所有病毒代碼段的總長度不超過30000。

輸出格式:

在文本文件WIR.OUT的第一行輸出一個單詞:

TAK——假如存在這樣的代碼;

NIE——如果不存在。

輸入輸出樣例

輸入樣例#1: 復制
3
01 
11 
00000
輸出樣例#1: 復制
NIE

題意:

給n個模式串,問能不能找到一個無限長的文本串,使得模式串沒有出現在文本串裏。

思路:

看到題目沒想法......看了題解

我們會發現正常的AC自動機都是在文本串中去匹配模式串,現在不要模式串出現,那麽也就是說希望Trie中被標記為模式串結尾的節點不要出現。我們將這個稱為危險標記。而想要無限長的文本串,其實也就是在匹配過程中能否找到這樣一個環,使得環上的節點都是安全的。

首先我們還是先建立fail數組,需要註意的是,如果一個節點的fail指針指向的節點是危險的,那麽他本身也是危險的。

因為一個節點x的fail指針指向的節點y表示的是以y作為結尾的前綴與以x為結尾的前綴的後綴匹配的最長部分,也就是說根節點到y一定是在根節點到x中出現過的。

然後dfs,用一個數組vis標記路徑,一個數組f標記是否訪問過。vis在dfs結束後要恢復,是用來判斷當前路徑是否形成環的。

 1 #include <iostream>
 2 #include <set>
 3 #include <cmath>
 4 #include <stdio.h>
 5
#include <cstring> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 using namespace std; 11 typedef long long LL; 12 #define inf 0x7f7f7f7f 13 14 int n; 15 const int maxn = 60000005; 16 17 struct Tree{ 18 int fail;//失配指針 19 int vis[2];//子節點位置 20 int ed;//標記有幾個單詞以這個節點結尾 21 }AC[maxn]; 22 string s; 23 int tot = 0; 24 25 void build(string s) 26 { 27 int len = s.length(); 28 int now = 0;//字典樹當前指針 29 for(int i = 0; i < len; i++){ 30 if(AC[now].vis[s[i] - 0] == 0){ 31 AC[now].vis[s[i] - 0] = ++tot; 32 } 33 now = AC[now].vis[s[i] - 0]; 34 } 35 AC[now].ed = 1; 36 } 37 38 void get_fail() 39 { 40 queue<int> que; 41 for(int i = 0; i < 2; i++){ 42 if(AC[0].vis[i] != 0){ 43 AC[AC[0].vis[i]].fail = 0; 44 que.push(AC[0].vis[i]); 45 } 46 } 47 while(!que.empty()){ 48 int u = que.front(); 49 que.pop(); 50 for(int i = 0; i < 2; i++){ 51 if(AC[u].vis[i] != 0){ 52 AC[AC[u].vis[i]].fail = AC[AC[u].fail].vis[i]; 53 if(AC[AC[u].fail].ed){ 54 AC[u].ed = 1; 55 } 56 que.push(AC[u].vis[i]); 57 } 58 else{ 59 AC[u].vis[i] = AC[AC[u].fail].vis[i]; 60 } 61 } 62 } 63 } 64 65 bool vis[maxn], f[maxn]; 66 void dfs(int rt) 67 { 68 vis[rt] = true; 69 for(int i = 0; i < 2; i++){ 70 if(vis[AC[rt].vis[i]]){ 71 printf("TAK\n"); 72 exit(0); 73 } 74 else if(!AC[AC[rt].vis[i]].ed && !f[AC[rt].vis[i]]){ 75 f[AC[rt].vis[i]] = true; 76 dfs(AC[rt].vis[i]); 77 } 78 } 79 vis[rt] = false; 80 } 81 82 int main() 83 { 84 scanf("%d", &n); 85 for(int i = 0; i < n; i++){ 86 cin>>s; 87 build(s); 88 } 89 AC[0].fail = 0; 90 get_fail(); 91 dfs(0); 92 printf("NIE\n"); 93 //cout<<s[maxid]<<endl; 94 //cout<<AC_query(s)<<endl; 95 return 0; 96 }

洛谷P2444 病毒【AC自動機】