题意:给你一个长度为n的单词表,一个文本串,问你这个文本串中出现了单词表中多少个单词;
解题思路:ac自动机的模板题,可以直接当模板用;
代码:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; const int maxn=1005000; struct node { node *next[27]; node *fail; int sum; }; char t[100]; char s[1000500]; int cnt; node *root; node *que[maxn]; int head,tail; node* newnode() { node *p=new node; for(int i=0;i<26;i++) p->next[i]=NULL; p->sum=0;p->fail=0; return p; } void build_trie(char *s) { node *p=root; int slen=strlen(s); for(int i=0;i<slen;i++) { int id=s[i]-'a'; if(p->next[id]==NULL) { p->next[id]=newnode(); } p=p->next[id]; } p->sum++; } void build_fail() { head=0; tail=1; que[head]=root; node *p; node *temp; while(head<tail) { temp=que[head++]; for(int i=0;i<26;i++) { if(temp->next[i]) { if(temp==root) { temp->next[i]->fail=root;//root的儿子的fail全部指向root; } else { //找temp儿子的指针; p=temp->fail;//temp的指向; while(p) { if(p->next[i])//如果temp的指向存在且和儿子相同,儿子指向为这个; { temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL) temp->next[i]->fail=root;//儿子指向根节点; } que[tail++]=temp->next[i]; } } } } void ac_automation(char *s) { node *p=root; int slen=strlen(s); for(int i=0;i<slen;i++) { int id=s[i]-'a'; while(!p->next[id]&&p!=root) p=p->fail; p=p->next[id]; if(!p) p=root; node *temp=p; while(temp!=root) { if((temp->sum)>=0) { cnt+=temp->sum; temp->sum=-1; } else break; temp=temp->fail; } } } void Delete(node *&top) { if(top==NULL) return; for(int i=0;i<26;i++) Delete(top->next[i]); delete top; } int main() { int tt; int n; scanf("%d",&tt); while(tt--) { root=newnode(); scanf("%d",&n); while(n--) { scanf("%s",t); build_trie(t); } scanf("%s",s); cnt=0; build_fail(); ac_automation(s); Delete(root); printf("%d ",cnt); } }
附上非指针版本:
代码:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int maxn=1000500; const int N=500050; int trie[N][26],fail[N],tot; int sum[N]; bool visit[N]; char s[maxn]; char t[60]; void build_trie(char *str) { int root=0; int slen=strlen(str); for(int i=0;i<slen;i++) { int id=str[i]-'a'; if(!trie[root][id]) { trie[root][id]=++tot; } root=trie[root][id]; } sum[root]++; } void build_fail() { queue<int>q; for(int i=0;i<26;i++) { if(trie[0][i]!=0) q.push(trie[0][i]); } while(!q.empty()) { int now=q.front();q.pop(); for(int i=0;i<26;i++) { if(!trie[now][i]) { trie[now][i]=trie[fail[now]][i]; continue; } fail[trie[now][i]]=trie[fail[now]][i]; q.push(trie[now][i]); } } } int ac(char *str) { int root=0,ans=0; int slen=strlen(str); for(int i=0;i<slen;i++) { visit[root]=1; int id=str[i]-'a'; int y=trie[root][id]; while(y&&!visit[y]) { visit[y]=1; if(sum[y]) { ans=ans+sum[y]; sum[y]=0; } y=fail[y]; } root=trie[root][id]; } return ans; } void init() { memset(trie,0,sizeof(trie)); memset(sum,0,sizeof(sum)); memset(visit,0,sizeof(visit)); memset(fail,0,sizeof(fail)); tot=0; } int main() { int n; int tt; scanf("%d",&tt); while(tt--) { init(); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",t); build_trie(t); } build_fail(); scanf("%s",s); printf("%d ",ac(s)); } }