洛谷P2444 病毒【AC自动机】

题目描述

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

示例:

例如如果{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 }

猜你喜欢

转载自www.cnblogs.com/wyboooo/p/9852607.html