HDU 2222 Keywords Search (AC自动机)

来源:互联网 发布:迈视高清网络摄像机 编辑:程序博客网 时间:2024/06/06 02:02

http://acm.hdu.edu.cn/showproblem.php?pid=2222
题意:给你一些单词,然后给你一段很长的话,问你话里有多少个之前给你的那些单词(重复的只算一次)。
方法:AC自动机,即把trie树和kmp的失效匹配相结合。

AC代码如下:

#include <iostream>#include <cstdio>#include <string.h>#include <queue>using namespace std;#define maxnode 500100#define sigma 26 struct ac_automation{    int ch[maxnode][sigma];    // maxnode 一般设置为 模式串数量*模式串长度     //char数组里存的都是位置信息,甚至包含了一些失效指针的信息。    bool val[maxnode];    int cnt[maxnode]; // count 数量    int last[maxnode]; // 储存着最后在查询时需要向上层回溯的地址。    int f[maxnode]; // fail指针 储存着指向的地址     int sz;  // the num of the trie    int ans; // answer    void clear(){ // 初始化        sz = 1;        ans = 0;        memset(ch[0],0,sizeof(ch[0]));        memset(val,0,sizeof(val));        memset(cnt,0,sizeof(cnt));    }    int idx(char c){         return c - 'a';    }    void insert(char s[]/*,int v*/){ // 构建trie树        int u = 0;        for(int i = 0; s[i];i++){            int c = idx( s[i] );            if(!ch[u][c]){                memset(ch[sz],0,sizeof(ch[sz]));                ch[u][c] = sz++;            }            u = ch[u][c];        }        cnt[u]++;        val[u] = 1;  //v;    }    void build(){ // 构建失效指针    //注意:构建失效匹配的时候是按照bfs的思想来的    //就是一层一层的,即:下层的f[]和last[]是根据上层的数据来的        f[0] = 0;        queue<int> q;        for(int i = 0;i < sigma;i++){            if(ch[0][i]){                f[ch[0][i]] = 0; // 第一层的节点的fail指针应该指向root(0)                q.push(ch[0][i]);// 放进队列                last[ch[0][i]] = 0;//上一层绝对是root(0)            }        }        while(!q.empty()){            int now = q.front();            q.pop();            for(int i = 0;i < sigma ;i++){                int son = ch[now][i];                if(!son){                    ch[now][i] = ch[f[now]][i];     // 提前将失效后指向此位置的的失效指针指向它应该指向的位置。     //因为这里找不到应有的字母,所以它应该等于自己的失效指针所指向的位置。                    continue;                }                q.push(son);                f[son] = ch[f[now]][i];                last[son] = val[f[son]] ? f[son] : last[f[son]];         /* 如果此处的fail指针指向的位置是之前插入单词的结尾,        那么son节点的上一层(last)就为它的失效指针,        否则去找他的失效指针的的上一层(此处一定有一个有意义的值,因为上层已经确定)*/            }        }    }    void find(char *s){        int u = 0;        for(int i = 0;s[i];i++){            int c = idx(s[i]);            u = ch[u][c];            if(val[u]){                print(u);            }            else{                print(last[u]);            }        }    }    void print(int u){        if(u){            ans += cnt[u];            cnt[u] = 0; // 因为只是找出有多少个匹配的,计入ans后需要清零,避免重复记录。            print(last[u]);        }    }}ac;char s[60];char text[1000100];int main(){    int ncase;    cin>>ncase;    while(ncase--){        int n;        cin>>n;        ac.clear();        for(int i = 0;i < n; i++){            scanf("%s",s);            ac.insert(s);        }        ac.build();        scanf("%s",text);        ac.find(text);        printf("%d\n",ac.ans);    }    return 0;}
1 0
原创粉丝点击