SPOJ6898 Substring Problem AC自动机

挺简单的AC自动机,只要求判断该串是否出现即可。只是有点坑,每一串可能出现多次。因此,要存储有哪一串序列序号的信息。

#include<stdio.h>  
#include<string.h>  
#include<queue>  
#include<vector>
using namespace std;
#define maxn 110000
int n,ch[maxn][52],fail[maxn],tot,root;
int ans[maxn],biao[maxn];   
char s[100010],fea[2010]; 
vector<int>val[maxn];//存储序号信息。
queue<int>q;  
int id(char t)
{
	if(t>='A'&&t<='Z')return t-'A';
	else return t-'a'+26;
}
int newnode()  
{  
    memset(ch[tot],0,sizeof(ch[tot]));  
	val[tot].clear();  
    return tot++;  
}  
void updatea(char *a,int no)  
{  
    int i,len=strlen(a),cur=root;  
    for(i=0;i<len;i++)  
    {  
        if(!ch[cur][id(a[i])])  
            ch[cur][id(a[i])]=newnode();  
        cur=ch[cur][id(a[i])];  
    }  
    val[cur].push_back(no);  
	biao[cur]=1;//用1有个好处:进行|运算。
}  
  
void getfail()  
{  
    fail[root]=root;  
    for(int i=0;i<26;i++)  
        if(ch[root][i])  
        {  
            fail[ch[root][i]]=root;  
            q.push(ch[root][i]);  
        }  
    while(!q.empty())  
    {  
        int cur=q.front();  
        q.pop();  
        for(int i=0;i<26;i++)  
            if(!ch[cur][i])  
                ch[cur][i]=ch[fail[cur]][i];  
            else  
            {  
                fail[ch[cur][i]]=ch[fail[cur]][i];
		biao[ch[cur][i]]|=biao[fail[ch[cur][i]]];//需注意
                q.push(ch[cur][i]);  
            }  
    }  
}  
void query()  
{  
    int cur=root,i,len=strlen(s);  
    for(i=0;i<len;i++)  
    {
	cur=ch[cur][id(s[i])];            
        int temp=cur;  
        while(temp!=root&&biao[temp])  
        {  
	    biao[temp]=0;
	    for(int j=0;j<val[temp].size();j++)
			ans[val[temp][j]]=1;
            temp=fail[temp]; 
        }  
    }   
  
}  
int main()  
{  
    while(~scanf("%s",s))  
    {  
        int i,j,k;  
        tot=0;
		memset(ans,0,sizeof(ans));
        root=newnode();
		scanf("%d",&n);
        for(i=1;i<=n;i++)  
        {  
            scanf("%s",&fea);  
            updatea(fea,i);
        }  
        getchar();  
        getfail();  
        query();  
		for(i=1;i<=n;i++)
			if(ans[i])
				printf("Y\n");
			else printf("N\n");
    }  
    return 0;  
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值