HDU 2222 Keywords Search (初学AC自动机)

我是通过http://wenku.baidu.com/view/4e70ccc38bd63186bcebbcb9.html的第二篇学会的

这篇也总结的很好,附带很多经典的习题http://www.cppblog.com/menjitianya/archive/2014/07/10/207604.html

这是bin神的总结:http://www.cnblogs.com/kuangbin/p/3164106.html

http://blog.csdn.net/mobius_strip/article/details/22549517


这是kss的板子:http://paste.ubuntu.com/10499866/

这个板子用了tire图的优化,即不需要失配回溯,效率大大提高


本题代码:

普通模版:

//826MS 28308K 
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 500500
#define M 1001000
char s[55];
char desc[M];
struct node{
    node *next[26];
    node *fail;
    int cnt;

}tire[MAXN],*que[MAXN],*root;
struct AC
{
    int L,head,tail;
    node *createnode(){
        memset(tire[L].next,0,sizeof(tire[L].next));
        tire[L].fail=NULL;
        tire[L].cnt=0;
        return &tire[L++];
    }
    void ini(){
        L=head=tail=0;
        root=createnode();
    }
    void Insert(char str[]){
        node *cur=root;
        for(int i=0;str[i];i++){
            int val=str[i]-'a';
            if(!cur->next[val]){
                cur->next[val]=createnode();
            }
            cur=cur->next[val];
        }
        cur->cnt++;
    }
    void build(){
        que[head++]=root;
        while(tail<head){
            node *cur=que[tail++];
            for(int i=0;i<26;i++){
                if(cur->next[i]!=NULL){
                    node *tmp=cur;
                    tmp=tmp->fail;
                    while(tmp!=NULL){
                        if(tmp->next[i]!=NULL){
                            cur->next[i]->fail=tmp->next[i];
                            break;
                        }
                        tmp=tmp->fail;
                    }
                    if(tmp==NULL) cur->next[i]->fail=root;
                    que[head++]=cur->next[i];
                }
            }
        }
    }
    int query(char str[]){
        int ans=0;
        node *cur=root;
        for(int i=0;str[i];i++){
            int val=str[i]-'a';
            while(cur!=root&&cur->next[val]==NULL) cur=cur->fail;
            cur= cur->next[val];
            cur=(cur==NULL) ? root:cur;
            node *tmp = cur;
            while(tmp!=root){ 
                ans+=tmp->cnt;
                tmp->cnt=0;
                tmp=tmp->fail;
            }
        }
        return ans;
    }
}ac;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ac.ini();
        int m;
        scanf("%d",&m);
        while(m--){
            scanf("%s",s);
            ac.Insert(s);
        }
        ac.build();
        scanf("%s",desc);
        printf("%d\n",ac.query(desc));
    }
    return 0;
}

tire图优化模版:(可见效率提高了很多)

//764MS 28308K 
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 500500
#define M 1001000
char s[55];
char desc[M];
struct node{
    node *next[26];
    node *fail;
    int cnt;
}trie[MAXN],*que[MAXN],*root;
struct AC{
    int head,tail,L;
    node* createnode(){
        trie[L].fail=NULL;
        memset(trie[L].next,0,sizeof(trie[L].next));
        trie[L].cnt=0;
        return &trie[L++];
    }
    void ini(){
        head=tail=L=0;
        root=createnode();

    }
    void Insert(char str[]){
        node *cur=root;
        for(int i=0;str[i];i++){

            int val=str[i]-'a';
            if(cur->next[val]==NULL)
                cur->next[val]=createnode();
           cur=cur->next[val];
        }
        cur->cnt++;
    }
    void build(){
        que[head++]=root;
        while(head>tail){
            node *cur=que[tail++];
            for(int i=0;i<26;i++){
                if(cur->next[i]!=NULL){
                    if(cur==root) cur->next[i]->fail=root;
                    else cur->next[i]->fail=cur->fail->next[i];
                    que[head++]=cur->next[i];
                }
                else {
                    if(cur==root) cur->next[i]=root;
                    else cur->next[i] = cur->fail->next[i];
                }
            }
        }
    }
    int query(char str[]){
        int ans=0;
        node *cur=root;
        for(int i=0;str[i];i++){

            int val=str[i]-'a';
            cur=cur->next[val];
            
                node *tmp=cur;
                while(tmp!=root){
                    ans+=tmp->cnt;
                    tmp->cnt=0;
                    tmp=tmp->fail;
                }
            
        }
        return ans;
    }
}ac;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ac.ini();
        int m;
        scanf("%d",&m);
        while(m--){
            scanf("%s",s);
            ac.Insert(s);
        }
        ac.build();
        scanf("%s",desc);
        printf("%d\n",ac.query(desc));
    }
    return 0;
}


进一步优化,询问的时候并不需要每次都跳到根,每次跳完就标记上-1,下次就不用跳了


//256MS 28308K 
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 500500
#define M 1001000
char s[55];
char desc[M];
struct node{
    node *next[26];
    node *fail;
    int cnt;
}trie[MAXN],*que[MAXN],*root;
struct AC{
    int head,tail,L;
    node* createnode(){
        trie[L].fail=NULL;
        memset(trie[L].next,0,sizeof(trie[L].next));
        trie[L].cnt=0;
        return &trie[L++];
    }
    void ini(){
        head=tail=L=0;
        root=createnode();

    }
    void Insert(char str[]){
        node *cur=root;
        for(int i=0;str[i];i++){

            int val=str[i]-'a';
            if(cur->next[val]==NULL)
                cur->next[val]=createnode();
           cur=cur->next[val];
        }
        cur->cnt++;
    }
    void build(){
        que[head++]=root;
        while(head>tail){
            node *cur=que[tail++];
            for(int i=0;i<26;i++){
                if(cur->next[i]!=NULL){
                    if(cur==root) cur->next[i]->fail=root;
                    else cur->next[i]->fail=cur->fail->next[i];
                    que[head++]=cur->next[i];
                }
                else {
                    if(cur==root) cur->next[i]=root;
                    else cur->next[i] = cur->fail->next[i];
                }
            }
        }
    }
    int query(char str[]){
        int ans=0;
        node *cur=root;
        for(int i=0;str[i];i++){

            int val=str[i]-'a';
            cur=cur->next[val];
            
                node *tmp=cur;
                while(tmp!=root && tmp->cnt != -1){
                    ans+=tmp->cnt;
                    tmp->cnt=-1;
                    tmp=tmp->fail;
                }
            
        }
        return ans;
    }
}ac;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ac.ini();
        int m;
        scanf("%d",&m);
        while(m--){
            scanf("%s",s);
            ac.Insert(s);
        }
        ac.build();
        scanf("%s",desc);
        printf("%d\n",ac.query(desc));
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值