AC自動機--Keywords Search

Keywords Search

In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. 
Wiskey also wants to bring this feature to his image retrieval system. 
Every image have a long description, when users type some keywords to find the image, the system will match the keywords with description of image and show the image which the most keywords be matched. 
To simplify the problem, giving you a description of image, and some keywords, you should tell me how many keywords will be match. 

Input

First line will contain one integer means how many cases will follow by. 
Each case will contain two integers N means the number of keywords and N keywords follow. (N <= 10000) 
Each keyword will only contains characters 'a'-'z', and the length will be not longer than 50. 
The last line is the description, and the length will be not longer than 1000000. 

Output

Print how many keywords are contained in the description.

Sample Input

1
5
she
he
say
shr
her
yasherhs

Sample Output

3

 AC自動機模板題:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Node{
	int cnt;//是否爲該單詞的最後一個結點 
	Node *fail;//失敗指針 
	Node *next[26];//字典樹中每個結點的各個節點(26個字母) 
}*queue[500005];//隊列,方便用BFS構造失敗指針 

char s[1000005];//主字符串 
char keyword[55];//需要查找的單詞 
Node *root;//頭結點 

void Init(Node *root){//每個結點的初始化 
	root->cnt=0;
	root->fail=NULL;
	for(int i=0;i<26;i++)
		root->next[i]=NULL;
}

void Build_trie(char *keyword){//構建字典樹 
	Node *p,*q;
	int i,v;
	int len=strlen(keyword);
	for(i=0,p=root;i<len;i++){//p=root -->>在root爲根節點開始建樹 
		v=keyword[i]-'a';
		if(p->next[v]==NULL){
			q=(struct Node *)malloc(sizeof(Node));//動態分配空間 
			Init(q);
			p->next[v]=q;//結點鏈接 
		}
		p=p->next[v];//指針移動到下一個結點
	}
	p->cnt++;//單詞最後一個結點cnt++,代表一個單詞 
}

void Build_AC_automation(Node *root){
	int head=0,tail=0;//隊列頭、尾指針
	queue[head++]=root;//先將root入隊 
	while(head!=tail){
		Node *p=NULL;
		Node *temp=queue[tail++];//彈出隊頭結點 
		for(int i=0;i<26;i++){
			if(temp->next[i]!=NULL){//找到實際存在的字符結點 
				//temp->next[i] 爲該結點,temp爲其父結點 
				if(temp==root)//若是第一層中的字符結點,則把該結點的失敗指針指向root 
					temp->next[i]->fail=root;
				else{
					//依次回溯該節點的父節點的失敗指針直到某節點的next[i]與該節點相同,
                	//則把該節點的失敗指針指向該next[i]節點; 
                	//若回溯到 root 都沒有找到,則該節點的失敗指針指向 root
					p=temp->fail;//將該結點的父結點的失敗指針給p 
					while(p!=NULL){
						if(p->next[i]!=NULL){//查看失敗指針所指節點p有無該字母的孩子節點 
							temp->next[i]->fail=p->next[i];
							break;
						}
						p=p->fail;
					}
					if(p==NULL)//讓該失敗指針所指結點的該字母節點(孩子節點)也指向root
						temp->next[i]->fail=root;
				}
				queue[head++]=temp->next[i];//每處理一個結點,都讓該結點的所有孩子依次入隊 
			}
		}
	}
}

int query(Node *root){
 	//i爲主串指針,p爲模式串指針 
	int i,v,count=0;
	Node *p=root;
	int len=strlen(s);
	for(i=0;i<len;i++){
		v=s[i]-'a';
		while(p->next[v]==NULL && p!=root)//由失敗指針回溯查找,判斷s[i]是否存在於字典樹中
			p=p->fail;
		p=p->next[v];//找到後p指針指向該結點 
		if(p==NULL)//若指針返回爲空,則沒有找到與之匹配的字符 
			p=root;
		Node *temp=p;//匹配該結點後,沿其失敗指針回溯,判斷其它結點是否匹配 
		while(temp!=root){//匹配結束控制 
			if(temp->cnt>=0){//判斷該結點是否被訪問 
				count+=temp->cnt;//由於cnt初始化爲 0,所以只有cnt>0時才統計了單詞的個數 
				temp->cnt=-1;//標記已訪問過 
			}
			else//結點已訪問,退出循環 
				break;
			temp=temp->fail;//回溯 失敗指針 繼續尋找下一個滿足條件的結點 
		}
	}
	return count;
}

void Freedom(Node* p)	//釋放內存 
{ 
    int i; 
    for(i=0;i<26;i++){ 
        if(p->next[i]!=NULL) 
            Freedom(p->next[i]); 
    } 
    delete p; 
} 

int main(){
	int T,n;
	scanf("%d",&T);
	while(T--){
		root=(struct Node *)malloc(sizeof(Node));
		Init(root);
		scanf("%d",&n);
		for(int i=0;i<n;i++){
			scanf("%s",keyword);
			Build_trie(keyword);
		}
		Build_AC_automation(root);
		scanf("%s",s);
		printf("%d\n",query(root));
		Freedom(root);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章