AC自动机 模板 hdu 2222

In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.
Wiskey also wants to bring this feature to his image retrieval system.
Every image have a long description, when users type some keywords to find the image, the system will match the keywords with description of image and show the image which the most keywords be matched.
To simplify the problem, giving you a description of image, and some keywords, you should tell me how many keywords will be match.
Input
First line will contain one integer means how many cases will follow by.
Each case will contain two integers N means the number of keywords and N keywords follow. (N <= 10000)
Each keyword will only contains characters ‘a’-‘z’, and the length will be not longer than 50.
The last line is the description, and the length will be not longer than 1000000.
Output
Print how many keywords are contained in the description.
Sample Input
1
5
she
he
say
shr
her
yasherhs
Sample Output
3

t个样例 5个单词,这一句话里面问你出现了多少个。

学了波模板

#include<stdio.h>
#define M 10010
struct trie{
    int sign;//是否为该单词的最后一个结点
    int fail;//失配指针
    int next[26];//26个字母方向的子结点
}t[M<<6];
int q[M<<6],head,tail,L;
char str[55],s[M<<8];
void Insert(char *a)//将单词插入字典树
{
    int i=0,p=0,j,x;
    while(a[i]){
        x=t[p].next[a[i]-'a'];
        if(x<0){//前面字符串未访问过此处,则申请新结点
            t[p].next[a[i]-'a']=x=++L;//数组模拟链表申请新结点(即++L操作)
            for(j=0;j<26;j++)t[x].next[j]=-1;
            t[x].fail=-1;t[x].sign=0;//初始化新结点信息
        }
        p=x;
        i++;
    }
    t[p].sign++;
}
void build_ACauto()//更新失配指针
{
    int i,x,y,p;
    t[0].fail=-1;
    q[tail++]=0;//将根放入队列
    while(head<tail){
        x=q[head++];//取队首元素
        for(i=0;i<26;i++){
            y=t[x].next[i];
            if(y>=0){
                if(!x)t[y].fail=0;//如果x为根结点,那么他的子结点的失配指针为头结点
                else{
                    p=t[x].fail;//取父结点的失配指针
                    while(p>=0){//如果失配指针不为空,继续找
                        if(t[p].next[i]>=0){//如果找到结点与相配
                            t[y].fail=t[p].next[i];//将失配指针指向它后退出循环
                            break;
                        }
                        p=t[p].fail;//否则继续往上找
                    }
                    if(p<0)t[y].fail=0;//如果最终还是没有找到,则失配指针指向根结点
                }
                q[tail++]=y;//将子结点存入队尾
            }
            else t[x].next[i]=t[t[x].fail].next[i];
        }
    }
}
int ACauto()//在字典树中查找s的子串在树中出现的次数
{
    int i=0,j,p=0,x,num=0;
    while(s[i]){
        j=s[i]-'a';
        while(t[p].next[j]<=0&&p)p=t[p].fail;//从字典树中找到相配结点或到达根时退出
        p=t[p].next[j];//指向找到的结点所对应字母
        if(p<=0)p=0;//如果没有找到,指针指向根结点
        x=p;
        while(x&&t[x].sign!=-1){//如果不是根结点且未访问过,则继续查找
            num+=t[x].sign;
            t[x].sign=-1;//把这句话去掉就可以把出现的全部次数都统计出来。
            //例如 ch 在 chch里面 这道题是1个,有的可能要求两个,就要去掉
            x=t[x].fail;//由失配指针向上查找
        }
        i++;
    }
    return num;
}
int main()
{
    int T,n,i;
    scanf("%d",&T);
    while(T--){
        head=tail=L=0;
        t[0].fail=-1;//初始化头结点信息
        t[0].sign=0;
        for(i=0;i<26;i++)t[0].next[i]=-1;
        scanf("%d",&n);
        while(n--){
            scanf("%s",str);
            Insert(str);//将读入的字符串插入字典树
        }
        build_ACauto();//更新字典树中的失配符
        scanf("%s",s);
        printf("%d\n",ACauto());//在字典树查找子串出现在字典树中的次数
    }
    return 0;
}

一个新的板子:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=500010;
const int maxm=500010;
const int SIGMA_SIZE=26;
int n;

char t[55];
char s[1000010];
struct AC
{
    int ch[maxm][26];
    int val[maxm];
    int fail[maxm],last[maxm];
    int sz;
    void clear(){memset(ch[0],0,sizeof(ch[0]));sz=1;}
    int idx(char x){return x-'a';}
    void insert(char *s)
    {
        int u=0;
        int 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]++;
    }
    void getfail()
    {
        queue<int> q;
        fail[0]=0;
        int u=0;
        for(int i=0;i<SIGMA_SIZE;i++)
        {
            u=ch[0][i];
            if(u){q.push(u);fail[u]=0;last[u]=0;}
        }
        while(!q.empty())
        {
            int r=q.front();q.pop();
            for(int i=0;i<SIGMA_SIZE;i++)
            {
                u=ch[r][i];
                if(!u){ch[r][i]=ch[fail[r]][i];continue;}
                q.push(u);
                int v=fail[r];
                while(v&&!ch[v][i])v=fail[v];
                fail[u]=ch[v][i];
                last[u]=val[fail[u]]?fail[u]:last[fail[u]];
            }
        }
    }
    int find(char *s)
    {
        int u=0,cnt=0;
        for(int i=0;s[i];i++)
        {
            int c=idx(s[i]);
            u=ch[u][c];
            int temp=0;//必须赋初值为0,表示如果下面两个判断都不成立的时候while可以正常执行
            if(val[u])
                temp=u;
            else if(last[u])
                temp=last[u];
            while(temp)
            {
                cnt+=val[temp];
                val[temp]=0;
                temp=last[temp];
            }
        }
        return cnt;
    }
}tree;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        tree.clear();
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",t);
            tree.insert(t);
        }
        tree.getfail();
        scanf("%s",s);
        printf("%d\n",tree.find(s) );
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值