hdu_1251统计难题(字典树Trie)

统计难题

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)
Total Submission(s): 31479    Accepted Submission(s): 12087


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

 

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

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

 

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

 

Sample Input
banana band bee absolute acm ba b band abc
 

 

Sample Output
2 3 1 0
字典树的典型应用,主要要会写建树和查找树的过程。遍树的时候要用dfs 我发现用指针写树很好写,所以就用指针了,哈哈
下面是代码,字典树可以保存成模板,
这个题让我长知识的是对于输入输出的限制,还有c++和G++对内存管理的机智不太一样,这个题就是用G++交的时候回抄内存,用c++交就过了
然后输入的时候总结一下:
因为是scanf("%d",&tm) 是不会读入最后的回车的,而scanf("%c“,&ch)会读回车,所以在%d后面要是回车再读入%c的话要加getchar()
scanf("%s",Str)是不会读入回车的,它会自动忽略回车,且到回车停止。
所以如果输入需要读入回车的话需要用gets();
 
这个题还可以用set的方法过掉,因为字符串不超过10所以可以直接就把每个字符串的所有前缀放到set里然后再处理
字典树方法:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <malloc.h>
 4 #include <iostream>
 5 using namespace std;
 6 #define MAXN 26
 7 typedef struct Trie {
 8     int v;//根据需要变化
 9     Trie *next[MAXN];
10     //next是表示每层有多少种类的数,如果只是小写字母,则26即可,
11     //若改为大小写字母,则是52,若再加上数字,则是62了
12 } Trie;
13 Trie root;
14 
15 void createTrie(char *str) {
16     int len = strlen(str);
17     Trie *p = &root, *q;
18     for(int i = 0; i < len; i++) {
19         int id = str[i]-'a';
20         if(p->next[id] == NULL) {
21             q = (Trie *)malloc(sizeof(root));
22             q->v = 1;//初始v==1
23             for(int j = 0; j < MAXN; j++)
24                 q->next[j] = NULL;
25             p->next[id] = q;
26             p = p->next[id];
27         } else {
28             p->next[id]->v++;
29             p = p->next[id];
30         }
31     }
32     // p->v = -1;//若为结尾,则将v改成-1表示
33 }
34 
35 int findTrie(char *str) {
36     int len = strlen(str);
37     Trie *p = &root;
38     for(int i = 0; i < len; i++) {
39         int id = str[i]-'a';
40         p = p->next[id];
41         if(p == NULL) //若为空集,表示不存以此为前缀的串
42             return 0;
43         //  if(p->v == -1)   //字符集中已有串是此串的前缀
44         //      return -1;
45     }
46     return p->v;
47     //return -1;   //此串是字符集中某串的前缀
48 }
49 int dealTrie(Trie* T) {
50     //动态字典树,有时会超内存,这是就要记得释放空间了
51     if(T==NULL)
52         return 0;
53     for(int i = 0; i < MAXN; i++) {
54         if(T->next[i]!=NULL)
55             dealTrie(T->next[i]);
56     }
57     free(T);
58     return 0;
59 }
60 int main() {
61     char str[15];
62     for(int i = 0; i < MAXN; i++)
63         root.next[i] = NULL;
64     while(gets(str) && str[0]!='\0')
65         createTrie(str);
66     memset(str, 0, sizeof(str));
67     while(scanf("%s", str) != EOF) {
68         int ans = findTrie(str);
69         printf("%d\n", ans);
70     }
71     return 0;
72 }

set方法:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <map>
 4 #include <cstring>
 5 #include <string>
 6 using namespace std;
 7 
 8 int main()
 9 {
10   char str[17];
11   map<string, int> m;
12   while(gets(str))
13   {
14     int len = strlen(str);
15     if (!len)
16     {
17       break;
18     }
19     for(int i = len; i > 0; i--)
20     {
21       str[i] = '\0';
22       m[str]++;
23     }
24   }
25   while(gets(str))
26   {
27     cout<<m[str]<<endl;
28   }
29 
30   return 0;
31 }

 

posted on 2016-07-16 16:16  若流芳千古  阅读(469)  评论(0编辑  收藏  举报

导航