HDOJ 2222 Keywords Search

Accepted 2222 593MS 30816K 2430 B G++

第一道 AC 自动机,理解了就好写;

需要注意字典可能重复,重复的不能按一次算。

# include <cstdio>
# include <cstring>
# include <queue>

using namespace std;

# define WORD_LEN 50 + 5
# define MAXN 10000 + 5
# define ALPHA_SIZE 26

int n, id;
char t[1000000 + 10];
char w[MAXN][WORD_LEN];

struct node
{
    node * fail;
    node * next[ALPHA_SIZE];
    int id;
    int isEnd;        // 字典里有重复的单词 
    node ()
    {
        fail = NULL;
        memset(next, 0, sizeof(next));
        id = 0;
        isEnd = 0;
    }
}* root;


int alpha_map(char ch)
{
    return ch - 'a';
}

void insert_trie(node * root, char *s)
{
    int c, i;
    node * p = root;
    for (i = 0; s[i]; ++i)
    {
        c = alpha_map(s[i]);
        if (NULL == p->next[c]) p->next[c] = new node;
        p = p->next[c];
    }
    ++(p->isEnd);
}

void build_trie(node * root)
{
    for (int i = 0; i < n; ++i)
        insert_trie(root, w[i]);
}

void build_AC_auto(node *root)
{
    int i;
    node *cur, *tmp;
    queue <node *> Q;

    // 根节点的子节点单独处理
    Q.push(root);
    for (i = 0; i < ALPHA_SIZE; ++i)
    {
        if (root->next[i])
        {
            root->next[i]->fail = root;
            Q.push(root->next[i]);
        }
    }Q.pop();    // 根节点出队

    // 更新非根节点子节点的 fail
    while (!Q.empty())
    {
        cur = Q.front(); Q.pop();    // 当前节点出队
        for (i = 0; i < ALPHA_SIZE; ++i)
        {
            if (cur->next[i])
            {
                tmp = cur->fail;            // 找到当前节点的 fail
                // 更新子节点的 fail
                while (tmp)
                {
                    if (tmp->next[i])
                    {
                        cur->next[i]->fail = tmp->next[i];
                        break;
                    }
                    tmp = tmp->fail;
                }
                // 没有找到可以匹配的
                if (NULL == tmp)
                {
                    cur->next[i]->fail = root;
                }
                // 将子节点入队
                Q.push(cur->next[i]);
            }
        }
    }
}

int search(char *t, node * root)
{
    int i, c, ret = 0;
    node *tmp, *p = root;

    for (i = 0; t[i]; ++i)
    {
        c = alpha_map(t[i]);
        while (root != p && NULL == p->next[c]) p = p->fail;
        p = p->next[c];
        if (NULL == p) p = root;
        tmp = p;
        while (tmp)
        {
            if (tmp->isEnd)
            {
                ret += tmp->isEnd;
                tmp->isEnd = 0;
            }
            tmp = tmp->fail;
        }
    }

    return ret;
}

void init(void)
{
    id = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%s", w[i]);
    scanf("%s", t);
}

void solve(void)
{
    root = new node;
    build_trie(root);
    build_AC_auto(root);
    printf("%d\n", search(t, root));
}

int main()
{
    int T;

    scanf("%d", &T);
    while (T--)
    {
        init();
        solve();
    }

    return 0;
}

/**/

posted on 2012-08-01 11:41  getgoing  阅读(380)  评论(0编辑  收藏  举报

导航