HDOJ-2222 Keywords Search 字典树+AC自动机(三叉树实现字典树)

来源:互联网 发布:js小图传给大图 编辑:程序博客网 时间:2024/04/29 03:50

啊啊,我还以为不可能成功的,放下了两天,今天无聊再敲一下。

原来我一直都读错题了呀。

只是计算出现的模式串的数目,重复的也只算一次。

把之前写的深度优先遍历子树都改成了广度优先遍历。

6000+k的内存,对比别人都是至少12000的内存,还是可以不错的。

代码量有点多和时间复杂度比trie树上的ac自动机大,并且一般acm里的都是二十六个字母,并不会卡那么点内存。

不管怎么说,证实三叉树可以构造AC自动机了。


/* 这个主要把递归深度优先遍历改成了非递归的广度优先的遍历 */#include <cstdio>#include <cstring>#include <queue>#include <iostream>using namespace std;typedef int Nodelink;const int maxn = 8000101;//内存池大小Nodelink Node[maxn][3];   //三叉树的节点.int cnt[maxn];   //以该节点为结束的字符串的数目。char elem[maxn];   //节点保存的字符。int top;   //模拟内存池地址char str[60];char pattern[1000010];Nodelink fail[maxn];int tque[maxn], tail, head;//不用STL的queueinline Nodelink newNode(char ch) //创建一个节点{    top ++;    Node[top][0] = Node[top][1] = Node[top][2] = 0;    cnt[top] = 0;    elem[top] = ch;    return top;}void Insert() //插入模式串{    int len = strlen(str);    Nodelink p = 1;    for(int i = 0; i < len; i++) {        if(!Node[p][2])            Node[p][2] = newNode(str[i]);        p = Node[p][2];        while(elem[p] != str[i]) { //二叉树插入元素,保证有序            if(str[i] < elem[p]) {                if(!Node[p][0]) Node[p][0] = newNode(str[i]);                p = Node[p][0];            }            else {                if(!Node[p][1]) Node[p][1] = newNode(str[i]);                p = Node[p][1];            }        }    }    cnt[p] ++; //以编号为p的结点为结尾的模式串的数目。}int que[28];int findFail(Nodelink fp, Nodelink p){    while(elem[fp] != elem[p])    {        if(elem[p] < elem[fp])            if(!Node[fp][0]) break;            else fp = Node[fp][0];        else            if(!Node[fp][1]) break;            else fp = Node[fp][1];    }    if(elem[fp] == elem[p])    {        fail[p] = fp;        return 1;    }    return 0;}void travelPre(Nodelink p, Nodelink pre){    int tp = 0, front = 0;    que[++tp] = p;    Nodelink tmp = 0;    while(front < tp)    {        p = que[++front];        tmp = fail[pre];        while(tmp && !findFail(Node[tmp][2], p)) tmp = fail[tmp];        if(tmp == 0) fail[p] = 1;        tque[++head] = p;        if(Node[p][0]) que[++tp] = Node[p][0];        if(Node[p][1]) que[++tp] = Node[p][1];    }}void getFail() //生成fail指针{    head = tail = 0;    tque[++head] = 1;    fail[1] = 0;    while(tail != head)    {        Nodelink pre = tque[++tail];        if(Node[pre][2])            travelPre(Node[pre][2], pre);    }}int ans = 0;int matchCH(char ch, Nodelink p, Nodelink &pre){    int tp = 0;    int front = 0;    que[++tp] = p;    while(front < tp)    {        p = que[++front];        if(elem[p] == ch)        {            pre = p;            int fp = p;            while(fp && cnt[fp] != -1)            {                ans += cnt[fp];                cnt[fp] = -1;                fp = fail[fp];            }            return 1;        }        if(Node[p][0])que[++tp] = Node[p][0];        if(Node[p][1])que[++tp] = Node[p][1];    }    return 0;}void match(){    int idx = 0;    Nodelink p = 1;    while(pattern[idx])    {        while(p && !matchCH(pattern[idx] , Node[p][2], p))            p = fail[p];        if(p == 0) p = 1;        idx ++;    }}int main(){    int t, n;    scanf("%d", &t);    while(t--)    {        top = 0;        ans = 0;        newNode('\0');        scanf("%d", &n);        for(int i = 0; i < n; i++)        {            scanf("%s",str);            Insert();        }        scanf("%s", pattern);        getFail();        match();        printf("%d\n", ans);    }    return 0;}


0 0
原创粉丝点击