qduoj 65 again and again 字典树

来源:互联网 发布:网络架构工程师干什么 编辑:程序博客网 时间:2024/05/18 21:40

题目链接


题意:

xx学习了Trie树后,向你问了一个问题,给定一个字符串集合S={str1, str2, ,strn}和一个字符串ss的后面接尽量少的字符,

使其属于集合S。当然如果s本身就属于Ss就是答案。如果多个,输出字典序最小的.


思路:

字典树中记录两个东西,一个是该单词的尾节点在字典树中是否出现过,也就是是否有该单词.另一个就是以某一字符串为前缀的单词

的最短长度是多少.

查找s时只需要先看s单词在字典树中是否实际存在,存在即为最短的,如果不存在的话就根据s单词为前缀的最短长度,按照字典序去

寻找长度最短的单词.直到找到为止.

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=5e5+10;const int inf=0x3f3f3f3f;char ss[20];int trie[maxn][27];int num[maxn]={0};int len[maxn];int t,n,q,pos=1;void insert(char s[])//在字典树中插入单词s  {      int c=0;      int l=strlen(s);    for(int i=0;s[i];i++)      {          int k=s[i]-'a';          if(trie[c][k]==0)//如果对应字符还没有值              {            num[pos]=0;  trie[c][k]=pos++;}        c=trie[c][k];          len[c]=min(l,len[c]);     }    num[c]=1; }void find(char s[]) {      int c=0;      for(int i=0;s[i];i++)      {          int k=s[i]-'a';          if(trie[c][k]==0)          {        printf("-1");        return ;}          c=trie[c][k];     }     printf("%s",s);     int mlen=len[c];     while(!num[c]) { for(int i=0;i<26;i++) {if(len[trie[c][i]]==mlen){printf("%c",i+'a');c=trie[c][i];break; }  } }   return ;}   int main(){scanf("%d",&t);int ca=1;while(t--){pos=1;memset(trie,0,sizeof(trie));memset(num,0,sizeof(num));memset(len,inf,sizeof(len));scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",ss);insert(ss);}printf("Case %d:\n",ca++);scanf("%d",&q);while(q--){scanf("%s",ss);find(ss);puts("");}}return 0;}