zoukankan      html  css  js  c++  java
  • HDU:1251-统计难题(字典树模板,动态建树,静态建树)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1251

    统计难题

    Time Limit: 4000/2000 MS (Java/Others)
    Memory Limit: 131070/65535 K (Java/Others)

    Problem Description

    Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).

    Input

    输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

    注意:本题只有一组测试数据,处理到文件结束.

    Output

    对于每个提问,给出以该字符串为前缀的单词的数量.

    Sample Input

    banana
    band
    bee
    absolute
    acm

    ba
    b
    band
    abc

    Sample Output

    2
    3
    1
    0


    解题心得:

    1. 标准的字典树,一般字典树就是用来求一个前缀的问题,字典树的建树方式其实和0-1树差不多,可以静态建树也可以动态建树,但是动态建树要注意malloc的运行效率很低,malloc不但要先在内存中去找是否存在可以开辟的空间,而且还会分配额外的字节用来记录内存块的信息。new也差不多。
    2. 对于字典树动态建树不太懂的人可以先去看看怎么手动写链表,建树就是一个和写链表差不多的过程,直接贴代码吧,都是套路很容易看懂的。
    3. 记得在HUD中交题的时候要交C++,G++会MLE,不知道为啥。

    动态建树malloc

    #include<stdio.h>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int sum;
        node *next[26];//字典树看字母大小写来看子节点有多少个
    };
    node *root,*current,*newnode;
    char s[15];
    
    void insert_tree()
    {
        current = root;
        int len = strlen(s);
        for(int i=0;i<len;i++)
        {
            int k = s[i] - 'a';
            if(current->next[k] == NULL)//按照树搜索下去找不到这个字母那么建立新的节点
            {
                newnode = (node *)malloc(sizeof(node));
                for(int i=0;i<26;i++)
                    newnode->next[i] = NULL;//新节点建立之后要将后面的指针指向空
                newnode->sum = 1;
                current->next[k] = newnode;
                current = newnode;
            }
            else
            {
                current = current->next[k];
                (current->sum)++;//记录在前缀中出现的次数
            }
        }
    }
    
    int query()
    {
        int len = strlen(s);
        current = root;//都要从根节点开始找
        for(int i=0;i<len;i++)
        {
            int k = s[i] - 'a';
            if(current->next[k] == NULL)//如果指向空那么说明没有以这个字符串为前缀的串
                return 0;
            current = current->next[k];
        }
        return current->sum;
    }
    
    int main()
    {
        root = (node *)malloc(sizeof(node));//根节点
        for(int i=0;i<26;i++)
            root->next[i] = NULL;
        while(gets(s) && s[0]!='')
            insert_tree();
        while(gets(s) && s[0]!='')
        {
            int ans = query();
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    动态建树new

    /*使用new来写其实和malloc写法差不多*/
    
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    struct node
    {
        int sum;
        node *child[26];
        node()
        {
            for(int i=0;i<26;i++)
                child[i] = NULL;
        }
    };
    node *newnode,*current,*root;
    char s[15];
    
    void insert_tree()
    {
        int len = strlen(s);
        current = root;
        for(int i=0;i<len;i++)
        {
            int k = s[i] - 'a';
            if(current->child[k] == NULL)
            {
                newnode = new node;
                newnode->sum = 1;
                current->child[k] = newnode;
                current = newnode;
            }
            else
            {
                current = current->child[k];
                (current->sum)++;
            }
        }
    }
    
    int query()
    {
        int len = strlen(s);
        current = root;
        for(int i=0;i<len;i++)
        {
            int k = s[i] - 'a';
            if(current->child[k] == NULL)
                return 0;
            current = current->child[k];
        }
        return current->sum;
    }
    
    int main()
    {
        root = new node;
        while(gets(s) && s[0] != '')
            insert_tree();
        while(gets(s) && s[0] != '')
        {
            int ans = query();
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    静态建树

    /*使用静态建树其实就是先开辟空间(数组),
    要使用的时候直接用指针指过去就行了,
    这样可以避免malloc和new效率低的问题*/
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+100;
    struct trie
    {
        int val;
        int sum,next[27];
    }tree[maxn<<2];//
    int num;
    char s[100];
    
    void add_trie()
    {
        int len = strlen(s),pos = 0;
        for(int i=0;i<len;i++)
        {
            int k = s[i] - 'a';
            if(!tree[pos].next[k])
                tree[pos].next[k] = num++;
            pos = tree[pos].next[k];
            tree[pos].sum++;
        }
    }
    
    int find()
    {
        int len = strlen(s),pos = 0;
        for(int i=0;i<len;i++)
        {
            int k = s[i] - 'a';
            if(!tree[pos].next[k])
                return 0;
            pos = tree[pos].next[k];
        }
        return tree[pos].sum;
    }
    
    int main()
    {
        memset(tree,0,sizeof(tree));
        num = 1;
        while(gets(s) && s[0] != '')
            add_trie();
        while(gets(s) && s[0] != '')
        {
            int ans = find();
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    C#深入浅出 修饰符(二)
    HDU 5785 Interesting
    HDU 5783 Divide the Sequence
    HDU 5781 ATM Mechine
    UVA 714 Copying Books
    uva 1471 Defense Lines
    UVA 11134 Fabled Rooks
    UVA 11572 Unique Snowflakes
    UVA 11093 Just Finish it up
    UVA 10954 Add All
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107204.html
Copyright © 2011-2022 走看看