hdu 2222 Keywords Search(AC自动机)

来源:互联网 发布:旅行翻译官软件 编辑:程序博客网 时间:2024/04/30 17:36

题意:

给你很多个单词,然后给你一篇文章,问给出的单词在文章中出现的次数。

解析:

直接套用AC自动机的模板。

注意:

每个单词在目标串中出现的话,只能记为一次。

my code

#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;const int maxnode = (int)1e6 + 10;const int sigma_size = 26;struct AC {    int ch[maxnode][sigma_size];    int fail[maxnode];    int last[maxnode];    int val[maxnode];    int sz;    int ans;    void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }    inline int idx(char c) { return c - 'a'; }    void insert(char *s) {        int u = 0, n = strlen(s);        for(int i = 0; i < n; i++) {            int c = idx(s[i]);            if(!ch[u][c]) {                memset(ch[sz], 0, sizeof(ch[sz]));                val[sz] = 0;                ch[u][c] = sz++;            }            u = ch[u][c];        }        val[u]++;    }    int find(char* tar) {        int n = strlen(tar);        int v = 0;        ans = 0;        for(int i = 0; i < n; i++) {            int c = idx(tar[i]);            while(v && !ch[v][c]) v = fail[v];            v = ch[v][c];            if(val[v]) print(v);            else if(last[v]) print(last[v]);        }        return ans;    }    void print(int j) {        while(j) {            ans += val[j]; //找到的话,将所有的val[j]都加进来            val[j] = 0; //然后将val[j]清空,之后就算有相同的单词也可以不用计算。            j = last[j];        }    }    int getFail() { //构造失配指针        queue<int> que;        //初始化队列        //root的子节点的失配指针都指向root。        for(int c = 0; c < sigma_size; c++) {            int u = ch[0][c];            if(u) { fail[u] = 0; que.push(u); last[u] = 0; }        }        //节点(字符为x)的失败指针指向:从x节点的父节点的fail节点回溯直到找到某节点的子节点也是字符x,没有找到就指向root。        //按照bfs顺序计算失配函数        while(!que.empty()) {            int r = que.front(); que.pop(); //取出队首,遍历当前的子节点            for(int c = 0; c < sigma_size; c++) {                int u = ch[r][c]; //当前的子节点                if(!u) continue; //且子节点不能为空                que.push(u); //将不为空的子节点存入队列                int v = fail[r]; //r = x 节点的父节点的fail节点                //从x节点的父节点的fail节点回溯,直到找到某节点的子节点也是字符x                //ch[v][c] == 0表示其子节点不是x,可以继续向上找;                //v != 0,fail[v]存在,表示还能向上找                while(v && !ch[v][c]) v = fail[v];                fail[u] = ch[v][c]; //找到某节点的子节点也是字符x,将u的失配指针指向最近的某节点的子节点也是字符x                last[u] = val[fail[u]] ? fail[u] : last[fail[u]];            }        }    }} ac;const int MAXN = (int)1e4 + 10;char key[MAXN][55];char tar[maxnode];int n;int main() {    int T;    scanf("%d", &T);    while(T--) {        ac.clear();        scanf("%d", &n);        for(int i = 0; i < n; i++) {            scanf("%s", key[i]);            ac.insert(key[i]);        }        ac.getFail();        scanf("%s", tar);        printf("%d\n", ac.find(tar));    }    return 0;}
0 0
原创粉丝点击