OJ:https://vjudge.net/problem/UVA-1449
简单翻译:
给定n个模式串和一个文本串T,只包含小写字母,你的任务是找出哪些模式串在T中出现的次数最多,输出对多的次数和出现最多的那个模式串。如果有多个次数相同的模式串,按输入顺序输出多个模式串。
这种多模但是长度比较短的提直接应该就能想到是AC自动机, 该题也就是一个非常明显的模板题,只需要很小的变动,因为我们要统计出现的次数,一个模式串可能会出现多次,且题中可能也会给出多个相同的模式串,最后还要输出出现次数最多的那个串,需要进行一点点的特殊处理。我们在trie的节点结构体上增加了一个index变量,用其来记录当前节点是哪个模式串的结尾,
这样我们在匹配到当前节点之后,就能给对应的模式串出现次数进行增加操作。
代码实现:我觉得代码如果看不懂的话,一定是不懂AC自动机,网上讲解很多,懂了的话,这个题可以作为练手题
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1000005
#define QUEUE_SIZE 70*26
#define max(x,y) x > y ? x : y
typedef struct{
// 当前是不是一个模式串的结束位置
int val;
int word[26];
// 失配节点
int fail;
// 当前节点如果是一个模式串的结束位置,index就用来记录当前是哪个模式串
int index;
}TrieNode;
typedef struct{
TrieNode nodes[71*150];
// 当前trie上的节点数量
int size;
}Trie;
int idx(char c);
void insert(char *s,int index);
void buildAc();
int isEmpty();
void push(int data);
int pop();
Trie trie;
// 存放模式串
char pattern[151][71];
// T串
char T[MAX];
// 队列相关,队列都要自己写,真惨
int queue[QUEUE_SIZE],pre=0,next=0,size=0;
int main()
{
int n = 0;
for(;1;){
trie.size = 1;
memset(trie.nodes[0].word,0,sizeof(trie.nodes[0].word));
pre = 0,next = 0,size= 0;
scanf("%d",&n);
if(n == 0){
return 0;
}
for(int i=0;i<n;i++){
scanf("%s",pattern[i]);
insert(pattern[i],i);
}
// 记录每个模式串出现的次数
int count[n];
memset(count,0,sizeof(count));
buildAc();
scanf("%s",T);
int len = strlen(T);
int curNode = 0;
for(int i=0;i<len;i++){
int nextNode = trie.nodes[curNode].word[idx(T[i])];
if(nextNode){
if(trie.nodes[nextNode].val){
count[trie.nodes[nextNode].index]++;
}
curNode = nextNode;
}else{
if(curNode!=0){
curNode = trie.nodes[curNode].fail;
i--;
}
}
}
int res = -1;
for(int i=0;i<n;i++){
res = max(res,count[i]);
}
printf("%d\n",res);
for(int i=0;i<n;i++){
if(count[i] == res){
printf("%s\n",pattern[i]);
}
}
}
return 0;
}
void push(int data){
size++;
queue[next++] = data;
if(next == QUEUE_SIZE){
next = 0;
}
}
int pop(){
size--;
int res = queue[pre++];
if(pre == QUEUE_SIZE){
pre = 0;
}
return res;
}
int isEmpty(){
return size == 0;
}
void buildAc(){
for(int i=0;i<26;i++){
if(trie.nodes->word[i]){
int index = trie.nodes->word[i];
push(index);
trie.nodes[index].fail = 0;
}
}
while(!isEmpty()){
int parentNode = pop();
for(int i=0;i<26;i++){
int curNode = trie.nodes[parentNode].word[i];
if(curNode){
push(curNode);
int pFail = trie.nodes[parentNode].fail;
while(pFail && !trie.nodes[pFail].word[i]){
pFail = trie.nodes[pFail].fail;
}
trie.nodes[curNode].fail = trie.nodes[pFail].word[i];
}
}
}
}
void insert(char *s,int index){
int curNode = 0,len = strlen(s);
for(int i=0;i<len;i++){
int index = idx(s[i]);
if(!trie.nodes[curNode].word[index]){
memset(trie.nodes[trie.size].word,0,sizeof(trie.nodes[0].word));
trie.nodes[trie.size].val = 0;
trie.nodes[curNode].word[index] = trie.size++;
}
curNode = trie.nodes[curNode].word[index];
}
trie.nodes[curNode].val += 1;
trie.nodes[curNode].index = index;
}
int idx(char c){
return c - 'a';
}