HDU2846 Repository(字典树)

Repository

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 5761    Accepted Submission(s): 1911

Problem Description

When you go shopping, you can search in repository for avalible merchandises by the computers and internet. First you give the search system a name about something, then the system responds with the results. Now you are given a lot merchandise names in repository and some queries, and required to simulate the process.

Input

There is only one case. First there is an integer P (1<=P<=10000)representing the number of the merchanidse names in the repository. The next P lines each contain a string (it‘s length isn‘t beyond 20,and all the letters are lowercase).Then there is an integer Q(1<=Q<=100000) representing the number of the queries. The next Q lines each contains a string(the same limitation as foregoing descriptions) as the searching condition.

Output

For each query, you just output the number of the merchandises, whose names contain the search string as their substrings.

Sample Input

20
ad
ae
af
ag
ah
ai
aj
ak
al
ads
add
ade
adf
adg
adh
adi
adj
adk
adl
aes
5
b
a
d
ad
s

Sample Output

0
20
11
11
2

Source

2009 Multi-University Training Contest 4 - Host by HDU

Recommend

gaojie   |   We have carefully selected several similar problems for you:  2852 2847 2845 2850 2851

题意 先给出 n个字符串,  再给出m个询问,每个询问给出一个字符串,问在先前的n个字符串中以它为子串的字符串有多少个

分析:普通字典树用来判断前缀的数量,所以在这里不能直接建树.那么如果把字符串的每个后缀都建树,那么现在的所有的前缀就相当于字符串的所有子串了.

但是这样会出现一个问题,比如abab 在计算以ab为子串的字符串的时候会被统计两次,所以我们需要对同一个字符串中的后缀在建树的时候进行标记

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN=26;  //只有小写字母
typedef struct Trie{
   int v;
   int num; //进行标记
   Trie *next[MAXN];
}Trie;
Trie *root;
char r[100];
void createTrie(char *str,int k)
{
    int len=strlen(str);
    Trie *p=root,*q;
    for(int i=0;i<len;i++)
    {
     int id=str[i]-‘a‘;
     if(p->next[id]==NULL)
     {
         q=(Trie*)malloc(sizeof(Trie));
         q->num=k;  //将后缀的每一部分都标记
         q->v=1;              //每次建立新节点进行初始化操作
         for(int j=0;j<MAXN;j++)
            q->next[j]=NULL;
         p->next[id]=q;
         p=p->next[id];
     }
     else
     {
          if(p->next[id]->num!=k){
         p->next[id]->v++;   //如果和标记不相等,代表不是同一字符串,才进行计数
         p->next[id]->num=k;
          }
         p=p->next[id];
     }
    }
}
int findTrie(char *str)
{
    int len=strlen(str);
    Trie *p=root;
    for(int i=0;i<len;i++)
    {
        int id=str[i]-‘a‘;
        p=p->next[id];
        if(p==NULL)
            return 0;
    }
    return p->v;
}
int  deal(Trie *T)
{
    int i;
    if(T==NULL)
        return 0;
    for(int i=0;i<MAXN;i++)
    {
        if(T->next[i]!=NULL)
            deal(T->next[i]);
    }
    free(T);
    return 0;
}
int main()
{
    char str[21];
    char s[100];
    int t,n,flag,cnt,m;
    root=(Trie*)malloc(sizeof(Trie));
    for(int i=0;i<MAXN;i++)
      root->next[i]=NULL;
      root->v=false; //初始化
      scanf("%d",&n);
       for(int i=0;i<n;i++)
      {
          scanf("%s",str);
         int len=strlen(str);
         for(int j=0;j<len;j++){
            for(int k=j;k<len;k++)
         {
             r[k-j]=str[k];
         }
            r[len-j]=‘\0‘;
            createTrie(r,i);
         }
      }
      scanf("%d",&m);
      for(int i=0;i<m;i++)
      {
          scanf("%s",s);
          printf("%d\n",findTrie(s));
      }
    //deal(root);
    return 0;
}

还需要注意的是,在这个题,每个字符数组都只使用一次,所以不用开二维数组进行记录

时间: 2024-10-10 21:00:49

HDU2846 Repository(字典树)的相关文章

hdu 2846 Repository 字典树

// hdu 2846 Repository 字典树 // // 题目大意: // // 有n个字符串,m个待询问的字符串,问这些字符串里面以该询问的 // 字符串为子串的字符串有多少个 // // 解题思路: // // 字典树,将字符串的所有子串插入到字典树中,并设立一个No.标识 // 以免重计数.最后查询就好了 // // 感悟: // // 这题的数据量有点大,虽然p是10000,但是长度是20,单个字符串的 // 最大子串数粗略的估计是 20 * 20 ,所以开的空间也要比较大.开始

HDU 2846 Repository(字典树,标记)

题目 字典树,注意初始化的位置~!!位置放错,永远也到不了终点了org.... 我是用数组模拟的字典树,这就要注意内存开多少了,,要开的不大不小刚刚好真的不容易啊.... 我用了val来标记是否是同一个串分解而来的,保存的是串的编号 num记录数目. //string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last); //把[first0,last0)之间的部分替换成[firs

HDU 2846 Repository (字典树 后缀建树)

Repository Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2932    Accepted Submission(s): 1116 Problem Description When you go shopping, you can search in repository for avalible merchandises

hdu 2846 Repository 字典树的一种变形

Repository Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2633    Accepted Submission(s): 1028 Problem Description When you go shopping, you can search in repository for avalible merchandises

[HDOJ2846]Repository(字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846 题意:求一堆串中有多少个以0开始的子串包含目标串. 可以把所有的串符合要求的子串放入字典树统计.这时候会有一个问题,那就是adddd这样的单词:样例中已经说明了,这样的单词明显是只算一次的.所以可以在字典树中打标记,每一个节点最后更新的时候的字符串是哪个. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef struct

HDU 2846 Repository(字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846 题目:输入个n个词典串,然后输入q个串,对这q个串分别输出每个串都是几个词典串的子串. 思路:因为要包含子串,比如abd,将串abd,bd,d都插入字典树,然后每个节点下统计子树个数,直接查找前缀就可以了.但需要注意dcda这种的,需要插入dcda,cda,da,a,这个时候d下面的子树应该是一个而不是2个,因为dcda和da属于同一个词典串.所以在插入的时候进行处理即可. 代码 #inclu

Repository HDU - 2846 字典树

题意:给出很多很多很多很多个 单词 类似搜索引擎一下 输入一个单词 判断有一个字符串包含这个单词 思路:字典树变体,把每个单词的后缀都扔字典树里面,这里要注意dd是一个单词 但是把d 和dd都放字典树 拿d匹配这一个单词会匹配两次 所以要开个数组记录一下上一个使该位置数量加一的字符串 如果该字符串不是同一个 那就可以加加了 TLE:还是数组大小的问题 字典树有毒!因为一个字符串可以拆成很多个后缀所以必须开大,开大了就过了... 1 #include<bits/stdc++.h> 2 using

hdu 1251 统计难题(字典树)

Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input 输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串. 注意:本题只有一组测试数据,处理到文件结束. Output 对于每个提

51nod round3# 序列分解(折半枚举+字典树)

小刀和大刀是双胞胎兄弟.今天他们玩一个有意思的游戏. 大刀给小刀准备了一个长度为n的整数序列.小刀试着把这个序列分解成两个长度为n/2的子序列. 这两个子序列必须满足以下两个条件: 1.他们不能相互重叠. 2.他们要完全一样. 如果小刀可以分解成功,大刀会给小刀一些糖果. 然而这个问题对于小刀来说太难了.他想请你来帮忙. Input 第一行给出一个T,表示T组数据.(1<=T<=5) 接下来每一组数据,输入共2行. 第一行包含一个整数n (2<=n<=40且为偶数). 第二行给出n