LA4670 AC自动机模版题

来源:互联网 发布:童装淘宝店铺简介 编辑:程序博客网 时间:2024/05/22 08:23

这里有个大神的博客:http://www.cnblogs.com/yefeng1627/archive/2013/05/23/3094566.html

题意:给你一些模式串和一个文本串,求在文本串中出现次数最多的模式串,输出次数和这些模式串。

文本串很长,模式串数量多但长度短,适用于AC自动机。

第一写AC自动机,基本照着敲的,不过稍微懂了些,希望早点掌握啦。

这题直接先建一个AC自动机,把串都编号,用map来防重复,在AC自动机里用一个cnt数组记录所有串的编号的出现次数,最后遍历所有串的边号,找出最多的次数,然后在遍历所有的字符串,找出串编号出现次数等于最大值的串。

代码:

#include<iostream>#include<cstdio>#include<vector>#include<string>#include<map>#include<queue>#include<cmath>#include<algorithm>#include<cstring>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define maxn 10005#define INF 0xfffffff#define mem(a,b) memset(a,b,sizeof(a))#define FOR(i,s,t) for(int i=s;i<=t;i++)#define ull unsigned long long#define ll long long#define N 20000#define M 1000006using namespace std;struct AC{    int ch[N][26],f[N],last[N];    int val[N],cnt[N];    int top;    void init()//基本都得置0    {        top=0;        memset(ch,0,sizeof(ch));        memset(f,0,sizeof(f));        memset(last,0,sizeof(last));        memset(val,0,sizeof(val));        memset(cnt,0,sizeof(cnt));    }    int NewNode()    {        int x=++top;        return x;    }    void insert(char *s,int num)//传参串的编号,类似trie的构建    {        int l=strlen(s);        int p=0;        for(int i=0; i<l; i++)        {            int c=s[i]-'a';            if(ch[p][c]==0)            {                ch[p][c]=NewNode();            }            p=ch[p][c];        }        val[p]=num;    }    void getfail()//求每个结点的f数组和last数组,分别表示失配指针和失配的模式串指针    {        queue<int> q;        for(int c=0; c<26; c++)//初始化所有只有一个字符的节点的失配指针都指向树根        {            int u=ch[0][c];            if(u)            {                f[u]=0;                last[u]=0;                q.push(u);            }        }        while(!q.empty())        {            int r=q.front();            q.pop();            for(int c=0; c<26; c++)            {                int u=ch[r][c];                if(!u)//如果r没有c这个子孙,那么就连到与r的失配指针指向的节点的c子孙                {                    ch[r][c]=ch[f[r]][c];                    continue;                }                q.push(u);//如果该节点存在,更新f和last数组                int v=f[r];                while(v&&!ch[v][c]) v=f[v];//更新f                f[u]=ch[v][c];                last[u]=val[f[u]]?f[u]:last[f[u]];//更新last            }        }    }    void find(char *s)    {        int n=strlen(s);        int p=0;        for(int i=0; i<n; i++)        {            int c=s[i]-'a';            p=ch[p][c];//这里直接匹配,可能匹配成功,也可能失败            if(val[p]) count(p);//如果匹配成功,并且有这个串,就计数            else if(last[p])//如果改点不是模式串,那就看他的失配指针            {                count(last[p]);            }        }    }    void count(int x)    {        if(x)//如果改点是模式串就计数,并且把有相同后记的所有节点递归计数        {            cnt[val[x]]++;            if(last[x])            {                count(last[x]);            }        }    }} ac;map<char*,int> mp;char text[M];char str[155][77];int main(){    int n;    while(scanf("%d",&n)==1)    {        if(!n) break;        mp.clear();        ac.init();        int tot=0;        for(int i=1; i<=n; i++)        {            scanf("%s",str[i]);            if(mp.count(str[i])==0) mp[str[i]]=++tot;            ac.insert(str[i],mp[str[i]]);        }        ac.getfail();        scanf("%s",text);        ac.find(text);        int k=0;        for(int i=1; i<=tot; i++)        {            k=max(k,ac.cnt[i]);        }        printf("%d\n",k);        for(int i=1; i<=n; i++)        {            if(ac.cnt[mp[str[i]]]==k)            {                printf("%s\n",str[i]);            }        }    }    return 0;}



原创粉丝点击