hdoj 2896 病毒侵袭(AC自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896

思路分析:题目为模式匹配问题,对于一个给定的字符串,判断能匹配多少个模式;该问题需要静态建树,另外需要对AC自动机的模板加以修改,

对于每个匹配的模式的最后一个单词的fail指针指向root,即可实现一个字符串进行多次模式匹配;

 

代码如下:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int KIND = 128;
const int MAX_NODE = 300 * 500;
const int MAX_M = 10000 + 100;
char str[MAX_M];
int vir_match[MAX_M];

struct Trie {
    int root, count;
    int next[MAX_NODE][KIND], fail[MAX_NODE], end[MAX_NODE];
    void Init()
    {
        count = 0;
        root = NewNode();
    }
    int NewNode()
    {
        for (int i = 0; i < KIND; ++i)
            next[count][i] = -1;
        end[count] = -1;
        return count++;
    }

    void Insert(char *str, int id)
    {
        int i = 0, k = 0;
        int now = root;

        while (str[i])
        {
            k = str[i];
            if (next[now][k] == -1)
                next[now][k] = NewNode();
            now = next[now][k];
            ++i;
        }
        end[now] = id;
    }

    void BuildAutomaton()
    {
        queue<int> Q;
        
        fail[root] = -1;
        Q.push(root);
        while (!Q.empty())
        {
            int now = Q.front();
            int p = -1;
            Q.pop();

            if (end[now] != -1)
                fail[now] = root;
            for (int i = 0; i < KIND; ++i)
            {
                if (next[now][i] != -1)
                {
                    if (now == root)
                        fail[next[now][i]] = root;
                    else
                    {
                        p = fail[now];
                        while (p != -1)
                        {
                            if (next[p][i] != -1)
                            {
                                fail[next[now][i]] = next[p][i];
                                break;
                            }
                            p = fail[p];
                        }
                        if (p == -1)
                            fail[next[now][i]] = root;
                    }
                    Q.push(next[now][i]);
                }
            }
        }
    }

    int Match(char *str)
    {
        int i = 0, k = 0, vir_count = 0;
        int p = root;

        while (str[i])
        {
            k = str[i];
            while (next[p][k] == -1 && p != root)
                p = fail[p];
            p = next[p][k];
            p = (p == -1) ? root : p;

            if (end[p] != -1)
            {
                vir_match[vir_count++] = end[p];
                p = fail[p];
            }
            ++i;
        }
        return vir_count;
    }
};

Trie root;

int main()
{
    int vir_num = 0, web_num = 0;
    int match_count = 0, web_matched = 0;

    while (scanf("%d\n", &vir_num) != EOF)
    {
        root.Init();
        for (int i = 0; i < vir_num; ++i)
        {
            gets(str);
            root.Insert(str, i + 1);
        }

        web_matched = 0;
        match_count = 0;
        root.BuildAutomaton();
        scanf("%d\n", &web_num);
        for (int i = 0; i < web_num; ++i)
        {
            int ans = 0;

            gets(str);
            ans = root.Match(str);
            sort(vir_match, vir_match + ans);
            if (ans)
            {
                web_matched++;
                printf("web %d: ", i + 1);
                for (int j = 0; j < ans - 1; ++j)
                    printf("%d ", vir_match[j]);
                printf("%d\n", vir_match[ans - 1]);
            }
        }
        printf("total: %d\n", web_matched);
    }
    return 0;
}

转载于:https://www.cnblogs.com/tallisHe/p/4665957.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值