HDU-2896-病毒侵袭(AC自动机)

题目链接

题目描述:按题目要求,将那些网页被那些病毒感染了,并且输出被感染网页数

AC自动机模板题

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<time.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>

#define pi acos(-1)
#define maxn 555
#define maxm 11111
#define INF 0x3F3F3F3F
#define eps 1e-8

#define pb push_back

#define mem(a) memset(a,0,sizeof a)

using namespace std;

const long long mod = 1000000007;
/**lyc**/
char str[maxn][222];   ///模式串
int n, m;
char a[maxm];
int ans_web;
#define STAUTS_NUM 100000
struct trie {
    ///next,fail,end都是基于第几个状态 状态就是一个字符串顺序
    int next[STAUTS_NUM][128], ///next数组表示 next[i][j]表示第i个状态后连j字符会变成什么状态,
                        ///注意最开始初始化的状态,在后面会被不断的优化
    fail[STAUTS_NUM],         ///失配数组,表示应该回到一个之前已匹配部分的最长后缀那里开始重新匹配。类似kmp
    end[STAUTS_NUM];          ///实际上就是表示哪些序列是模式串中有的,1,0,表示
  //  int next2[maxn][26]; /**这个数组是我这个程序中另外设的,用来储存最原始的next数组,有特殊用**/
    int num[maxn];///每个单词出现的次数
    int f[STAUTS_NUM];///每个节点对应的单词编号

    int root,  ///根节点状态,默认是0
    cnt;       ///状态数
    int new_node () {  ///对于一个没有的状态,对他新建一个节点
        memset (next[cnt], -1, sizeof next[cnt]);
        end[cnt++] = 0;
        return cnt-1;
    }
    void init () {    ///初始化这棵字典树
        cnt = 0;
        root = new_node ();
        memset (f, -1, sizeof f);
    }
    void insert (char *buf, int pos) { ///字典树插入一个模式串
        int len = strlen (buf);
        int now = root;
        for (int i = 0; i < len; i++) {
            int id = buf[i];
            if (next[now][id] == -1) {  ///没有这个状态就新建一个节点
                next[now][id] = new_node ();
            }
            now = next[now][id];
        }
        end[now]++;
        f[now] = pos;   ///标记一下这个状态对应第几个字符串
    }
    void build () {   ///构建fail数组

        /**这里备份一下next数组
        for(int i = 0; i < cnt; i++) {
            for(int j = 0; j < 26; j++) {
                next2[i][j] = next[i][j];
            }
        }

        这里备份一下next数组**/


        queue <int> q;
        fail[root] = root;
        for (int i = 0; i < 128; i++) {
            if (next[root][i] == -1) {
                next[root][i] = root;
            }
            else {
                fail[next[root][i]] = root;
                q.push (next[root][i]);
            }
        }
        while (!q.empty ()) {
            int now = q.front (); q.pop ();
            for (int i = 0; i < 128; i++) {
                if (next[now][i] == -1) {
                    next[now][i] = next[fail[now]][i];
                }
                else {
                    fail[next[now][i]] = next[fail[now]][i];
                    q.push (next[now][i]);
                }
            }
        }

    }
    int query (char *buf, int pos) {

        memset (num, 0, sizeof num);
        int len = strlen (buf);
        int now = root;
      //  int res = 0;
        int fa = 0;
        for(int i = 0; i < len; i++) {
            int id = buf[i];
            now = next[now][id];
            int tmp = now;
            while (tmp != root) {
                if (end[tmp]) {
                    num[f[tmp]] += end[tmp];
                    fa = 1;
                }
                tmp = fail[tmp];//沿着失配边走
            }
        }
        if(fa == 1) {
            ans_web++;
            printf("web %d:", pos);
            for(int i = 1; i <= n; i++) {
                if(num[i]) {
                    printf(" %d", i);
                }
            }
            printf("\n");
        }


    }
}ac;
int main() {
    while(scanf("%d", &n) != EOF) {
        ans_web = 0;
        ac.init();
        for(int i = 1; i <= n; i++) {
            scanf("%s", str[i]);
            ac.insert(str[i], i);
        }
        ac.build();
        scanf("%d", &m);
        for(int i = 1; i <= m; i++) {
            scanf("%s", a);
            ac.query(a, i);
        }
        printf("total: %d\n", ans_web);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值