动态字典树_统计子串(HDU_2846)

解题思路:这一题要求我们找到输入的词是字典中多少个词的子串,而不仅仅是其前缀,因此建树的时候需要将词典中词分解成不同前缀加入到树中,即是说将形如abc的词拆成abc,bc,c,三种形式,这样就相当于找输入的词是词典中多少词的前缀,需要注意的是,对于同一个词分解出的多个前缀,如果他们之间有相同的话,这种前缀,只算作一种,即是说形如abca之类的词,会分解出abca,a两种前缀,但因为是同一个词分解出来的,所以算作一种。判断是否是同一个词分解出来的需要给每个输入的词及其分解出的前缀加以相同的id进行编号。

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

#define M 26

struct node{
    int end,count;
    node *child[M];
    node()
    {
        count = 0;
        end = -1;
        memset(child,NULL,sizeof(child));
    }
};

char id[M];

void clear(node *root)
{
    for(int i=0;i<M;i++)
    {
        if(root->child[i] != NULL)
            clear(root->child[i]);
    }
    delete root;
}

void insert(node *root, char *str, int end)
{
    node *p = root;
    int len = strlen(str);
    for(int i=0; i<len; i++)
    {
        int k = str[i] - 'a';
        if(p->child[k] == NULL)
            p->child[k] = new node;
        p = p->child[k];
        if(p->end != end)
        {
            p->count++;
            p->end = end;
        }
    }
}

int find(node *root, char *str)
{
    node *p = root;
    int len = strlen(str);
    for(int i=0; i<len; i++)
    {
        int k = str[i] - 'a';
        if(p->child[k] == NULL)
            return 0;
        p = p->child[k];
    }
    return p->count;
}

int main(int argc, char* argv[])
{
    #ifdef __MYLOCAL
    freopen("in.txt","r",stdin);
    #endif

    int p,q;
    node *root = new node;

    scanf("%d",&p);
    while(p--)
    {
        scanf("%s",id);
        int len = strlen(id);
        for(int i=0; i<len; i++)
            insert(root,id + i,p);
    }
    scanf("%d",&q);
    while(q--)
    {
        scanf("%s",id);
        printf("%d\n",find(root,id));
    }

    clear(root);

    return 0;
}

 

posted on 2013-07-22 20:35  lk1993  阅读(323)  评论(0编辑  收藏  举报