UVA1449 AC自动机

来源:互联网 发布:淘宝图片保护怎么弄 编辑:程序博客网 时间:2024/05/16 15:29

给定n个由小写字母组成的字符串和一个文本串T,找出哪些字符串在T中出现的次数最多。

AC自动机应用之一:统计每个模板串在原字符串中出现的次数

AC自动机的精华:利用last函数,将模板串的所有子串连接起来,只要沿着边走就可以遍历所有模板串的所有子串

对于重复的模板串题目要求重复输出,因此需要对每一个字符串对应一个序号,这样相同的字符串可以有两个不同的序号。


#include<cstring>#include<queue>#include<cstdio>#include<map>#include<string>using namespace std;const int SIGMA_SIZE=26;const int MAXNODE=11000;const int MAXS=150+10;map<string,int> ms;struct AC{    int ch[MAXNODE][SIGMA_SIZE];    int f[MAXNODE];//fail函数    int val[MAXNODE];//字符串结尾结点    int last[MAXNODE];//输出链表的下一个节点    int cnt[MAXS];    int sz;    void init(){        sz=1;        memset(ch[0],0,sizeof(ch[0]));        memset(cnt,0,sizeof(cnt));        ms.clear();    }    //字符c的编号    int idx(char c){        return c-'a';    }    //插入字符串    void insert(char *s,int v){        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]=v;        ms[string(s)]=v;//记录每个字符串的编号索引    }    //递归打印以节点j结尾的所有字符串    //找出所有可以匹配的字符串,“打印”(称为遍历更合适)并计数    void print(int j){        if(j){            cnt[val[j]]++;            print(last[j]);        }    }    //在T中找模板    int find(char *T){        int n=strlen(T);        int j=0;        for(int i=0;i<n;i++){            int c=idx(T[i]);            while(j&&!ch[j][c]) j=f[j];//顺着失配边走,直到可以匹配为止            j=ch[j][c];            if(val[j]) print(j);            else if(last[j]) print(last[j]);//找到了?        }    }    //计算fail函数    void getfail(){        queue<int> q;        f[0]=0;        //初始化队列        for(int c=0;c<SIGMA_SIZE;c++){            int u=ch[0][c];            if(u) { f[u]=0;q.push(u);last[u]=0; }        }        while(!q.empty()){            int r=q.front();q.pop();            for(int c=0;c<SIGMA_SIZE;c++){                int u=ch[r][c];                if(!u) continue;                q.push(u);                int v=f[r];                while(v&&!ch[v][c]) v=f[v];                f[u]=ch[v][c];                last[u]=val[f[u]]?f[u]:last[f[u]];            }        }    }};AC ac;char text[1000001],P[151][80];int n,T;int main(){    //freopen("a.txt","r",stdin);    while(scanf("%d",&n)!=EOF){        if(!n) break;        ac.init();        for(int i=1;i<=n;i++){            scanf("%s",P[i]);            ac.insert(P[i],i);        }        ac.getfail();        scanf("%s",text);        ac.find(text);        int best=-1;        for(int i=1;i<=n;i++)            if(ac.cnt[i]>best) best=ac.cnt[i];        printf("%d\n",best);        for(int i=1;i<=n;i++)            if(ac.cnt[ms[string(P[i])]]==best) printf("%s\n",P[i]);    }    return 0;}



0 0