Keywords Search---hdu2222(AC自动机 模板)

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

一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过;

本题就是最基础的模板;在此之前需要理解kmp和字典树(trie);

Trie树有3个基本性质:

(1) 根节点不包含字符,除根节点外每一个节点都只包含一个字符;

(2) 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;

(3) 每个节点的所有子节点包含的字符都不相同。

1.  AC自动机算法分为3步:

(1)构造一棵Trie树;
(2)构造失败指针;

构造失败指针的过程概括起来就一句话:设这个节点上的字母为x,沿着他父亲的失败指针走,

直到走到一个节点,他的儿子中也有字母为x的节点。然后把当前节点的失败指针指向那个字符

也为x的儿子。如果一直走到了root都没找到,那就把失败指针指向root。

1: root的子节点的失败指针都指向root。

2: 节点(字符为x)的失败指针指向:从X节点的父节点的fail节点回溯直到找到某节点的子节点也是字符x,没有找到就指向root。

(3)根据AC自动机,搜索待处理的文本。

从root节点开始,每次根据读入的字符沿着自动机向下移动。 当读入的字符,在分支中不存在时,递归走失败路径。

如果走失败路径走到了root节点, 则跳过该字符,处理下一个字符。 因为AC自动机是沿着输入文本的最长后缀移

动的,所以在读取完所有输入文本后,最后递归走失败路径,直到到达根节点, 这样可以检测出所有的模式。

搜索的步骤:
  1. 从根节点开始一次搜索;
  2. 取得要查找关键词的第一个字符,并根据该字符选择对应的子树并转到该子树继续进行检索;
  3. 在相应的子树上,取得要查找关键词的第二个字符,并进一步选择对应的子树进行检索。
  4. 迭代过程……
  5. 在某个节点处,关键词的所有字符已被取出,则读取附在该节点上的信息,即完成查找。

    匹配模式串中出现的单词。当我们的模式串在Trie上进行匹配时,如果与当前节点的关键字不能继续匹配的时候,

    就应该去当前节点的失败指针所指向的节点继续进行匹配。

匹配过程出现两种情况:
  1. 当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符, 此时只需沿该路径走向下一个节点继续匹配即可   ,目标字符串指针移向下个字符继续匹配;
  2. 当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。
 重复这2个过程中的任意一个,直到模式串走到结尾为止。

哎,看了大神的讲解:不会AC自动机基础的可以参考一下:

http://www.cppblog.com/menjitianya/archive/2014/07/10/207604.html

http://blog.csdn.net/niushuai666/article/details/7002823

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;

const int N = 1e6+7;
char MumStr[N];
struct node
{
    node *next[26], *fail;
    int leaf;
};

void AddTrie(char s[], node *head)
{
    node *p = head;
    for(int i=0; s[i]; i++)
    {
        int k = s[i] - ‘a‘;

        if(p->next[k] == NULL)
            p->next[k] = new node();

        p = p->next[k];
    }
    p->leaf ++;
}
void GetFail(node *head)
{
    queue<node*>Q;
    Q.push(head);
    while(Q.size())
    {
        node *p = Q.front();
        Q.pop();
        for(int i=0; i<26; i++)
        {
            if(p->next[i] != NULL)
            {
                node *t = p->fail;
                while(t != NULL)
                {
                    if(t->next[i] != NULL)
                    {
                        p->next[i]->fail = t->next[i];
                        break;
                    }
                    t = t->fail;
                }
                if(t == NULL)
                    p->next[i]->fail = head;
                Q.push(p->next[i]);
            }
        }
    }
}
int Query(node *head)
{
    int sum = 0;
    node *p = head;
    for(int i=0; MumStr[i]; i++)
    {
        int k = MumStr[i] - ‘a‘;
        while(p->next[k] == NULL && p != head)
            p = p->fail;
        if(p->next[k] == NULL)
            continue;
        node *t = p = p->next[k];
        while(t!=head && t->leaf != -1)
        {
            sum += t->leaf;
            t->leaf = -1;
            t = t->fail;
        }
    }
    return sum;
}
int main()
{
    int T, n;
    char s[110];
    scanf("%d", &T);
    while(T--)
    {
        node *head = new node();
        scanf("%d", &n);
        for(int i=0; i<n; i++)
        {
            scanf("%s", s);
            AddTrie(s, head);
        }
        GetFail(head);
        scanf("%s", MumStr);
        int ans = Query(head);
        printf("%d\n", ans);
    }
    return 0;
}

时间: 2024-08-05 17:50:07

Keywords Search---hdu2222(AC自动机 模板)的相关文章

Keywords Search HDU2222 AC自动机模板题

ac自动机说起来很复杂,其实和kmp是一样的思路,都是寻找相同前后缀,减少跳的次数.只要理解了kmp是怎么求next数组的,ac自动机bfs甚至比knp还好写. 这里大致说一下kmp求next数组的方法吧,假设现在要求第c个字符的next值(假设这个c很大,这样画图出来比较清晰方便理解),因为遍历过程中我们已经知道了第c-1个字符的next为x(假设比c小很多),即next[c-1] = x.那就代表我们知道了a[1]-a[x]这一段和a[c-1-x]-a[c-1]这一段是相等的对吧. 那么现在

HDU-2222 Keywords Search(AC自动机--模板题)

题目大意:统计一共出现了多少次模板串. 题目分析:AC自动机的模板题.不过这题有坑,相同的模板串不能只算一次. 代码如下: # include<iostream> # include<cstdio> # include<queue> # include<map> # include<string> # include<cstring> # include<algorithm> using namespace std; co

【HDU-2222】Keywords Search(AC自动机模板)

AC自动机的模板题,自己手敲了一遍模板. 添加失配边的时候,对每个结点的26条字母边链接的子结点扫一遍,如果结点存在,那么这个子结点的失配边就是主结点失配边对应结点链接的子节点. 如果结点不存在,那么这个结点就直接连到主结点失配边对应结点链接的子节点. 感觉AC自动机好难懂啊...QAQ 11885512 2014-10-16 16:22:43 Accepted 2222 687MS 26688K 2772 B G++ KinderRiven #include<stack> #include&

HDU 2222 Keywords Search(AC自动机模板题)

题意:给出一个字符串和若干个模板,求出在文本串中出现的模板个数. 思路:因为有可能有重复的模板,trie树权值记录每个模板出现的次数即可. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map>

HDU 2222:Keywords Search(AC自动机模板)

http://acm.hdu.edu.cn/showproblem.php?pid=2222 KMP是单模式串匹配的算法,而AC自动机是用于多模式串匹配的算法.主要由Trie和KMP的思想构成. 题意:输入N个模式串,再给出一个文本串,求文本串里出现的模式串数目. 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <al

Keywords Search (ac 自动机)

Keywords Search  Problem Description In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey also wants to bring this feature to his image retrieval system. Every image have a long description, when users typ

HDU 2222——Keywords Search(AC自动机)

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 34020    Accepted Submission(s): 11009 Problem Description In the modern time, Search engine came into the life of everybody like

[hdu2222] [AC自动机模板] Keywords Search [AC自动机]

AC自动机模板,注意!ch,Fail,lab数组的大小不是n而是节点个数,需要认真计算! 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <ctime> 7 #include <cstdlib> 8 #include <queue>

hdu2222(ac自动机模板)

先推荐两篇写的很好的ac自动机blog: http://blog.csdn.net/creatorx/article/details/71100840 http://blog.csdn.net/niushuai666/article/details/7002823 正题 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意: 给出 n 个模式串以及一个 主串, 问有多少个模式串在主串中出现过 思路: ac自动机模板题 代码: 1 #inc

【HDU2222】Keywords Search(AC自动机)

Problem Description In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.Wiskey also wants to bring this feature to his image retrieval system.Every image have a long description, when users type some keywords to