• 洛谷P2444 病毒【AC自动机】


    题目描述

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

    示例:

    例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。

    任务:

    请写一个程序:

    1.在文本文件WIR.IN中读入病毒代码;

    2.判断是否存在一个无限长的安全代码;

    3.将结果输出到文件WIR.OUT中。

    输入输出格式

    输入格式:

    在文本文件WIR.IN的第一行包括一个整数n(nle 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
    ");
    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
    ");
    93     //cout<<s[maxid]<<endl;
    94     //cout<<AC_query(s)<<endl;
    95     return 0;
    96 }
  • 相关阅读:
    (译+原)std::shared_ptr及std::unique_ptr使用数组
    (转+原)ipp "No dlls were found in the Waterfall procedure"
    (原)vs2013编译boost1.60库
    (原+转)VS2013:正在从以下位置加载符号
    (原)直方图的相似性度量
    (原)Opencv中直方图均衡和图像动态范围拉伸的代码
    JAVA 8 新特性 Stream API 创建
    JAVA 8 新特性 Stream API 介绍
    JAVA 8 新特性 方法引用
    JAVA 8 新特性 函数式接口
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9852607.html
Copyright © 2020-2023  润新知