zoukankan      html  css  js  c++  java
  • hdu 2222 Keywords Search

    题目大意:

    给你一些单词,和一个字符串,问你这个字符串中含有多少个上面的单词。

    解题分析:

    这是多模匹配问题,如果用KMP的话,对每一个单词,都跑一遍KMP,那么当单词数量非常多的时候,耗时会非常多,所以这里用到了AC自动机,这是一种类似于Trie树的数据结构,但是同时,它也用到了KMP算法中 next数组的思想。

    下面是AC自动机指针形式的题解:

    #include <iostream>
    #include <cstring>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    
    const int N =10000*50+10;
    struct node {
        int cnt;
        node *fail;
        node *next[26];
        node() {
            cnt=0;
            fail=NULL;
            for(int i=0;i<26;i++) next[i]=NULL;
        }
    }*que[N];   node *root;
    
    void ins(char *s) {
        int len = strlen(s);
        node *tmp,*rt=root;
        for(int i=0;i<len;i++) {
            int id=s[i]-'a';
            if(rt->next[id]==NULL)
                rt->next[id]=new node();
            rt=rt->next[id];
        }
        rt->cnt++;
    }
    
    void build_AC() {
        int st=0,ed=0;
        que[ed++]=root;
        while (st < ed) {
            node *tmp, *rt=que[st++];
            for(int i=0;i<26;i++) {
                if(rt->next[i]!=NULL) {
                    if(rt==root)
                        //单个字符,没有后缀,因此失配指向root
                        rt->next[i]->fail=root;
                    else {
                        //不断找父亲的fail指针下面有next[id]的后缀
                        tmp = rt->fail;
                        while (tmp!=NULL) {
                            if(tmp->next[i]!=NULL) {
                                rt->next[i]->fail = tmp->next[i];
                                break;
                            }
                            tmp=tmp->fail;
                        }
                        if(tmp==NULL)
                            rt->next[i]->fail=root;
                    }
                    que[ed++]=rt->next[i];
                }
            }
        }
    }
    
    int match(char *s) {
        node *rt=root;
        int len=strlen(s);
        int res=0;
        for(int i=0;i<len;i++) {
            int id= s[i]-'a';
            if(rt->next[id]!=NULL) rt=rt->next[id];
            else {
                rt=rt->fail;
                while (rt!=NULL && rt->next[id]==NULL) rt=rt->fail;
                if(rt != NULL) rt=rt->next[id];
                else rt=root;
            }
            node *tmp = rt;
            if(tmp->cnt > 0) {
                while (tmp!=NULL) {
                    res += tmp->cnt;
                    tmp->cnt=0;
                    tmp = tmp->fail;
                }
            }
        }
        return res;
    }
    int T,n; char word[1000000+10],str[60];
    
    int main () {
        scanf("%d",&T);
        while (T--) {
            root=new node();
            scanf("%d",&n);
            for(int i=0;i<n;i++) scanf("%s",str),ins(str);
            build_AC();
            scanf("%s",word); printf("%d
    ",match(word));
        }
        return 0;
    }

    参考blog/资料:

      https://www.bilibili.com/video/av6295004

      https://www.cnblogs.com/00isok/p/9426990.html

  • 相关阅读:
    第二题
    第一题
    biancheng
    用泰勒展开式计算sin
    矩阵求和
    1
    ti
    实验10
    实验9
    实验8
  • 原文地址:https://www.cnblogs.com/Draymonder/p/9503316.html
Copyright © 2011-2022 走看看