[HDU 2222] Keywords Search [AC自动机]

来源:互联网 发布:java工程师年龄要求 编辑:程序博客网 时间:2024/06/05 04:52

Keywords Search
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 51531 Accepted Submission(s): 16603

Problem Description
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

Author
Wiskey

Recommend
lcy | We have carefully selected several similar problems for you: 2896 3065 2243 2825 3341

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<queue>using namespace std;int T,n;#define maxn 1000001char tmp[maxn];class Trie{    #define sigma_size 26    public :        Trie* next[sigma_size];        bool flag;        int cnt;//可能有相同的.         Trie* fail;//Fail指针         Trie()        {            fail = NULL;            cnt = 0;             for(int i=0;i<sigma_size;i++)next[i]=NULL;        }};Trie *root;void Insert(char* s,Trie* root){    Trie* p = root;    while(*s)    {        int index = *s - 'a';        if(p->next[index]==NULL)            p->next[index] = new class Trie;        p = p->next[index];        s++;    }    p->flag=1;    p->cnt++;}queue<Trie*> q;void getFail(Trie* root){    root->fail = NULL;    q.push(root);    while(!q.empty())    {        Trie* u = q.front();q.pop();        for(int i=0;i<sigma_size;i++)        {            if(u->next[i]!=NULL)            {                if(u == root)u->next[i]->fail = root;                else                                {                    Trie* p =  u->fail;                    while(p!=NULL)                    {                        if(p->next[i]!=NULL)                        {                            u->next[i]->fail=p->next[i];                            break;                        }                        p = p->fail;                    }                    if(p==NULL)                    {                        u->next[i]->fail=root;                    }                }                q.push(u->next[i]);            }        }    }}int ans = 0;int search(Trie *root,char *s){    int ans = 0;    Trie *p = root;    while(*s != '\0'){        while(!p->next[*s-'a'] && p != root){            p = p->fail;        }        p = p->next[*s-'a'];        if(p == NULL)p = root;        Trie *temp = p;        while(temp != root && temp->cnt != -1){            ans += temp->cnt;            temp->cnt = -1;            temp = temp->fail;        }        ++s;    }    return ans;}int main(){    scanf("%d",&T);    while(T--)    {        ans = 0;        root = new Trie;        scanf("%d",&n);        for(int i=1;i<=n;i++)        {            scanf("%s",tmp);            Insert(tmp,root);        }        getFail(root);//获取Fail指针                scanf("%s",tmp);        printf("%d\n",search(root,tmp));            }    return 0;}

(ps:指针动态建树如何处理多组数据?每处理完一组后free掉再建?浪费许多额外时间。但是如果不free掉,就必须init一次(初始化)判断也会多一个状态,是否为NULL,在当前第t组数据时是否建到这里(vis),orz。所以这道题最好还是用下面的代码。。直接覆盖。。至于上面是怎么过的。。orz。。对每组数据建了个Trie树。。因为数据小所以没有爆空间)
下面是数组版本的代码0.0

#include <queue>#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int Siz = 26, Maxl = 1000010, MS = 5000000;int ch[MS][Siz], Cnt[MS], root, totN, Fail[MS], ans;int NewNode() {    Cnt[++totN] = 0;    memset(ch[totN], 0, sizeof ch[totN]);    return totN;}void Insert(char *S) {    int cur = root;    char idx;    while (*S) {        idx = *S - 'a';        if (ch[cur][idx]) {            cur = ch[cur][idx];        } else {            cur = ch[cur][idx] = NewNode();        }        ++S;    }    ++Cnt[cur];}void BuildFail() {    queue<int>q;    Fail[root] = root;    for (int i = 0; i < Siz; ++i) if (ch[root][i]) {        Fail[ch[root][i]] = root;        q.push(ch[root][i]);    }    int f, p;    while (!q.empty()) {        p = q.front(); q.pop();        for (int i = 0; i < Siz; ++i) if (ch[p][i]) {            f = Fail[p];            while (!ch[f][i] && f) f = Fail[f];            if (ch[f][i]) Fail[ch[p][i]] = ch[f][i];            else Fail[ch[p][i]] = root;            q.push(ch[p][i]);        }    }}void Count(int u) {    while (u) {        ans += Cnt[u]; Cnt[u] = 0;        u = Fail[u];    }}void Search(char *S) {    ans = 0;    int cur = root, idx, f;    while (*S) {        idx = *S - 'a';        if (ch[cur][idx]) {            cur = ch[cur][idx];        } else {            f = Fail[cur];            while (!ch[f][idx] && f) f = Fail[f];            if (ch[f][idx]) cur = ch[f][idx];            else cur = root;        }        if (Cnt[cur]); Count(cur);        ++S;    }} char tmpS[Maxl];void Work() {    int N;    scanf("%d", &N);    totN = -1; root = NewNode();    getchar();    while (N--) {        gets(tmpS);        Insert(tmpS);    }    BuildFail();    gets(tmpS);    Search(tmpS);    printf("%d\n", ans);}int main() {    int T;    scanf("%d", &T);    while (T--) {        Work();    }    return 0;   }
1 0