hdu 2896 病毒侵袭 AC自动机入门题

来源:互联网 发布:双色球选红球算法 编辑:程序博客网 时间:2024/06/05 00:35

点击打开链接

题意:给出若干个模式串n<=5e2长度<=2e2和主串个m<=1e3长度<=1e4 问每个主串中包含哪几个模式串,输出编号.

建立字典时 把单词结尾设为编号,设p[i]为模式串是在某个母串中出现,对每个母串跑AC自动机即可 

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=201*500; int flag;struct Aho{int chd[N][128],v[N],f[N],last[N],sz,ans;int p[N];//p[i] 模式串i是否出现 void init(){memset(p,0,sizeof(p));sz=1;ans=0;memset(v,0,sizeof(v));memset(f,0,sizeof(f));memset(chd[0],0,sizeof(chd[0]));}void insert(char *s,int x){int u=0,i=0;while(s[i]){int id=s[i]-' ';if(!chd[u][id]){memset(chd[sz],0,sizeof(chd[sz]));chd[u][id]=sz++;}u=chd[u][id];i++; }v[u]=x;//记录编号 }void getFail(){queue<int> q;f[0]=0;for(int c=0;c<128;c++){int u=chd[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<128;c++){int u=chd[r][c];if(!u){chd[r][c]=chd[f[r]][c];continue;//补边 }q.push(u);int x=f[r];//找到前缀i和后缀c相等 while(x&&!chd[x][c]) x=f[x];f[u]=chd[x][c];//last作用:若到i匹配成功,将母串中以后缀i结尾的单词进行快速匹配//当母串中以后缀i的和某个模式串S匹配成功,则该模式串沿着失配边,找到前缀为模式串T,T和后缀s相同,同样也和母串后缀i相同 last[u]=v[f[u]]? f[u]:last[f[u]];}}}void solve(int j,int x){if(!j) return;if(v[j]){flag++;p[v[j]]=1;//}solve(last[j],x);}void find(char *s,int x){int n=strlen(s),j=0;for(int i=0;i<n;i++){int id=s[i]-' ';j=chd[j][id];//trieif(v[j])solve(j,x);//匹配成功 看还有没有其他串和后缀i匹配else if(last[j])solve(last[j],x);// }}}aho;char s[10001];int main(){int n,m;while(cin>>n){aho.init();char dic[600];int tot=0;for(int i=1;i<=n;i++){scanf("%s",dic);aho.insert(dic,i);}aho.getFail();cin>>m;for(int i=1;i<=m;i++){memset(aho.p,0,sizeof(aho.p));flag=0;int t=0;scanf("%s",s);aho.find(s,i);if(flag){printf("web %d:",i);for(int k=1;k<=n;k++){if(aho.p[k]){t++;printf(" %d",k);if(t>=flag)break;}}tot++;printf("\n");}}printf("total: %d\n",tot);}return 0;} 


0 0
原创粉丝点击