AC自動機(KMP+字典樹)
阿新 • • 發佈:2019-01-02
AC自動機(KMP+字典樹) 題目:輸入N個串,判斷有多少個搜尋串的子串 In out 1 4 7 a ab abc abcd abcde abcdef abcdefg abcd #include<bits/stdc++.h> using namespace std; char str[1000000+100]; struct node{ int count; //當前結點有多少個字串共同享用 struct node *next[26]; //指向26個字母的指標 struct node *fail; //失配指標 void init(){ //建構函式 for(int i = 0; i < 26; i++) next[i] = NULL; count = 0; fail = NULL; } } *root; void insert(){ int len, k; //開始建樹 node *p = root; //先把指標指向根 len = strlen(str); //求出串長 for(k = 0; k < len; k++){ //遍歷一次字串 int pos = str[k] - 'a'; //讀出當前字元在字母表中的位置 if( p->next[pos] == NULL ){ //如果為空則開闢新結點,初始化,P指向往下指 p->next[pos] = new node; p->next[pos]->init(); p = p->next[pos]; } else //即使憶開闢,也要往下指 p = p->next[pos]; } p->count++; //當前結點使用次數加一,注意是最後字元的結點才加!! } void getfail() { int i; node *p = root, *son, *temp; //指向根的指標,兒子指標,臨時指標 queue <struct node *> que; //廣搜 que.push(p); //把根壓入佇列 while( !que.empty() ){ //只要佇列不為空就就迴圈 temp = que.front(); //讀出最前面的結點 que.pop(); //從佇列刪去 for(i = 0; i < 26; i++){ son = temp->next[i]; //遍歷一次全部兒子,每次記為SON if(son != NULL){ //存在這個兒子 if(temp == root) {son->fail = root;} //temp是根則son失配時必指向根 else{ p = temp->fail; //讀出temp的失配指標 while( p ) { //除了根肯定不為空 if(p->next[i]){ //如果temp失配指標結點有一樣的兒子 son->fail=p->next[i]; //則son指向那個兒子 break; } p=p->fail; //如果沒有這個兒子就遞迴失配! } if(!p) son->fail=root; //廣搜下失配指標為空的只有根故son指向根 } que.push(son);//把指向這個兒子的指標壓入佇列 } } } } void query() { int len, i, cnt = 0; len = strlen(str); node *p, *temp; p = root; for( i = 0; i < len; i++) { int pos = str[i]-'a'; while( !p->next[pos]&&p!=root )//因為根是沒有失配指標的 p = p->fail;//遞迴失配 p = p->next[pos];//訪問兒子 if( !p ) p=root;//沒有這個兒子就回到根開始 temp = p;//儲存當前掃到的結點P,用TEMP來計算 while( temp!=root ) { if(temp->count >= 0) { cnt += temp->count; temp->count = -1; } else break; temp = temp->fail;//當前結點的所有失配點的數量都會被計算,因為本題是求有幾個串是模板串的子串 } } printf("%d\n",cnt); } int main() { int cas,n; //案例數 scanf("%d",&cas); while(cas--) { root=new node; root->init(); root->fail=NULL; scanf("%d",&n); //一共有多少個子串 int i; getchar(); //吸收回車符 for(i=0;i<n;i++) { gets(str); //輸入N個子串並插入字典樹,str全域性變數不用傳參 insert(); } getfail(); //計算失配指標 gets(str); //輸入搜尋串 query(); //詢問搜尋串出出現,子串的次數 } return 0; }