题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27301
题意:
t个测试数据
n个模式串
母串
n个模式串
问:
求每个模式串在母串中出现的次数
思路:
对于每个模式串,记录该串的单词结尾在字典树中的节点标号
在母串匹配字典树时,沿着失配边走过的节点都是母串的子串, 因此在失配过程中记录子串出现次数
注意沿失配边走的时候:
while(temp && val[temp] ) temp为当前节点,val[temp] 为当前节点是 几个模式串的单词结尾
这里应当写
while(temp)
因为即使当前节点不为 单词结尾,也需要沿失配边走下去,所以一定要去掉val[temp]
#include <stdio.h> #include <string.h> #include <queue> using namespace std; inline int Max(int a,int b){return a>b?a:b;} inline int Min(int a,int b){return a>b?b:a;} #define maxnode 262144 #define sigma_size 26 struct Trie{ int ch[maxnode][sigma_size]; int val[maxnode]; int haha[maxnode]; int f[maxnode]; int sz; void init(){ sz=1; memset(ch,0,sizeof(ch)); memset(val, 0, sizeof(val)); memset(f,0,sizeof(f)); memset(haha,0,sizeof(haha)); } int idx(char c){ return c-'a'; } int insert(char *s){ int u = 0, len = strlen(s); for(int i = 0;i < len;i++){ int c = idx(s[i]); if(!ch[u][c]) ch[u][c] = sz++; u = ch[u][c]; } val[u] ++; return u; } void getFail(){ queue<int> q; for(int i = 0; i<sigma_size; i++) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ int r = q.front(); q.pop(); for(int c = 0; c<sigma_size; c++){ int u = ch[r][c]; if(!u)continue; q.push(u); int v = f[r]; while(v && ch[v][c] == 0) v = f[v]; //沿失配边走上去 如果失配后有节点 且 其子节点c存在则结束循环 f[u] = ch[v][c]; } } } void find(char *T){ int len = strlen(T), j = 0; for(int i = 0; i < len; i++){ int c = idx(T[i]); while(j && ch[j][c]==0) j = f[j]; j = ch[j][c]; int temp = j; while(temp){ haha[temp]++; temp = f[temp]; } } } }; Trie ac; char P[1000011]; int ans[505]; int main(){ int t,cas = 1,i,n;scanf("%d",&t); while(t--){ ac.init(); scanf("%d",&n); scanf("%s",P); for(i = 1; i <= n; i++) { char S1[505]; scanf("%s",S1); ans[i] = ac.insert(S1); } ac.getFail(); ac.find(P); printf("Case %d:\n",cas++); for(i=1;i<=n;i++) printf("%d\n",ac.haha[ ans[i] ]); } return 0; } /* 2 5 ababacbabc aba ba ac a abc 3 lightoj oj light lit */