HDU-3065 病毒侵袭持续中(注意多组输入)

AC自动机模板题,判断各个串分别出现多少次

#include 
#include 
#include 
using namespace std;
const int N = 5e4 + 5;
const int M = 2e6 + 5;
const int C = 1e4 + 5;
int trie[N][128]; //字典树
int cntword[N];  //记录该单词出现次数
int fail[N];     //失败时的回溯指针
int num[N];
int flag[C];
int cnt[C];
int tot = 0;
char s[M], ss[C][55];
void insertWords(char *s, int l, int t){
    int root = 0;
    for(int i = 0; i < l; ++i){
        int next = s[i];
        if(!trie[root][next])
            trie[root][next] = ++tot;
        root = trie[root][next];
    }
    ++cntword[root];      //当前节点单词数+1
    num[root] = t;
}
void getFail(){
    queue<int> q;
    for(int i = 0; i < 128; ++i){      //将第二层所有出现了的字母扔进队列
        if(trie[0][i]){
            fail[trie[0][i]] = 0;
            q.push(trie[0][i]);
        }
    }

//fail[now]    ->当前节点now的失败指针指向的地方
tire[now][i] -> 下一个字母为i+'a'的节点的下标为tire[now][i]
    while(!q.empty()){
        int now = q.front();
        q.pop();

        for(int i = 0; i < 128; ++i){      //查询26个字母
            if(trie[now][i]){
                //如果有这个子节点为字母i+'a',则
//让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)
                //有点绕,为了方便理解特意加了括号

                fail[trie[now][i]] = trie[fail[now]][i];
                q.push(trie[now][i]);
            }
            else//否则就让当前节点的这个子节点
                //指向当前节点fail指针的这个子节点
                trie[now][i] = trie[fail[now]][i];
        }
    }
}


void query(char *s, int l){
    int now = 0;
    for(int i = 0; i < l; ++i){    //遍历文本串
        now = trie[now][s[i]];  //从s[i]点开始寻找
        for(int j = now; j && cntword[j] != -1; j = fail[j]){
            //一直向下寻找,直到匹配失败(失败指针指向根或者当前节点已找过).
            if(cntword[j] == 1){
            	int idx = num[j];
            	flag[idx] = 1;
            	++cnt[idx];
            }
        }
    }
}

void init(){
	memset(cntword, 0, sizeof(cntword));
	memset(trie, 0, sizeof(trie));
	tot = 0;
}
int main() {
	int n;
	while(scanf("%d", &n) != EOF){		
		for(int i = 1; i <= n; ++i){
		    scanf("%s", ss[i]);
			insertWords(ss[i], strlen(ss[i]), i);
		}
		fail[0] = 0;
		getFail();
		scanf("%s", s);
		query(s, strlen(s));
		for(int i = 1; i < C; ++i){
			if(flag[i]){
				printf("%s: %d\n", ss[i], cnt[i]);
			}
		}
		memset(trie, 0, sizeof(trie));
		memset(cntword, 0, sizeof(cntword));
		memset(flag, 0, sizeof(flag));
		memset(cnt, 0, sizeof(cnt));
		tot = 0;
	}
    return 0;
}


你可能感兴趣的:(AC自动机)