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
 
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]='';
            createTrie(r,i);
         }
      }
      scanf("%d",&m);
      for(int i=0;i<m;i++)
      {
          scanf("%s",s);
          printf("%d
",findTrie(s));
      }
    //deal(root);
    return 0;
}

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

 
原文地址:https://www.cnblogs.com/a249189046/p/7469533.html