ACM常用模板——字典树

模型:单词匹配
   
   
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. using namespace std;
  5. struct node
  6. {
  7. bool flag;
  8. string s;
  9. node *next[26];
  10. node()
  11. {
  12. flag=0;
  13. memset(next,0,sizeof(next));
  14. }
  15. };
  16. node *p,*root;
  17. void Insert(string s,string v)
  18. {
  19. p=root;
  20. for(int i=0;i<s.size();i++)
  21. {
  22. int id=s[i]-'a';
  23. if(p->next[id]==NULL) p->next[id]=new node();
  24. p=p->next[id];
  25. }
  26. p->flag=1;//终点标志,若改成++,则得出该单词出现的次数
  27. p->s=v;
  28. }
  29. string Query(string s)
  30. {
  31. p=root;
  32. for(int i=0;i<s.size();i++)
  33. {
  34. int id=s[i]-'a';
  35. if(p->next[id]==NULL) return "";
  36. p=p->next[id];
  37. }
  38. if(p->flag==0) return "";
  39. return p->s;
  40. }
  41. int main()
  42. {
  43. root=new node();
  44. string s,v;
  45. cin>>s;
  46. while(cin>>s&&s!="END")
  47. {
  48. cin>>v;
  49. Insert(v,s);
  50. }
  51. cin>>s;
  52. getline(cin,s);
  53. while(getline(cin,s)&&s!="END")
  54. {
  55. for(int i=0;i<s.size();i++)
  56. {
  57. v="";
  58. while(s[i]>='a'&&s[i]<='z') v+=s[i++];
  59. string f=Query(v);
  60. if(f=="") cout<<v<<s[i];
  61. else cout<<f<<s[i];
  62. }
  63. cout<<endl;
  64. }
  65. return 0;
  66. }

hud2846

大意:给定你一些商品的信息save(字符串),然后输入需要查询的字符串str,如果存在一个字符串save使得str是save的子串。

思路:字典树的变形,如存在"abcd",则"bcd", "cd", "d",都需要插入字典树中。如果存在"abab"的话,有可能"ab"会重复计数,所以需要一个特定的序列号来区分是否是同一序列中的子串。

我们可以定义一个value,若value相同,则跳过,若不同,则+1后更新value。

 
   
   
  1. #define LL long long
  2. #define lson l,m,rt<<1
  3. #define rson m+1,r,rt<<1 | 1
  4. using namespace std;
  5. struct node
  6. {
  7. int num,id;
  8. node *next[26];
  9. node() { num=0;id=0;memset(next,0,sizeof(next));}
  10. };
  11. node *p,*root;
  12. void Insert(string s,int cnt)
  13. {
  14. p=root;
  15. for(int i=0;i<s.size();i++)
  16. {
  17. int id=s[i]-'a';
  18. if(p->next[id]==0)
  19. {
  20. p->next[id]=new node();
  21. p=p->next[id];
  22. p->id=cnt;
  23. p->num++;
  24. }
  25. else
  26. {
  27. p=p->next[id];
  28. if(p->id!=cnt)
  29. {
  30. p->id=cnt;
  31. p->num++;
  32. }
  33. }
  34. }
  35. }
  36. int Query(string s)
  37. {
  38. p=root;
  39. for(int i=0;i<s.size();i++)
  40. {
  41. int id=s[i]-'a';
  42. if(p->next[id]==0) return 0;
  43. p=p->next[id];
  44. }
  45. return p->num;
  46. }
  47. void Delete(node *rt)
  48. {
  49. for(int i=0;i<26;i++)
  50. {
  51. if(rt->next[i])
  52. {
  53. Delete(rt->next[i]);
  54. delete(rt->next[i]);
  55. }
  56. }
  57. }
  58. int main()
  59. {
  60. int n;
  61. string s;
  62. cin.sync_with_stdio(false);
  63. while(cin>>n)
  64. {
  65. root=new node();
  66. for(int i=0;i<n;i++)
  67. {
  68. cin>>s;
  69. for(int j=0;j<s.size();j++)
  70. Insert(s.substr(j),i);
  71. }
  72. int m;
  73. cin>>m;
  74. for(int i=0;i<m;i++)
  75. {
  76. cin>>s;
  77. cout<<Query(s)<<endl;
  78. }
  79. Delete(root);
  80. }
  81. return 0;
  82. }
hdu 1247

给出若干个单词,找出其中能够由其它两个单词连接组合而成的单词。比如上面sample中的"ahat"能够由"a"和"hat"拼凑而成,"hatword"="hat"+"word".

只要将这些字符串插入到字典树中去,并设置结束标记,并用字符串数组保存起来。然后再依次把每个字符串放到字典树中查询即可。

   
   
  1. #include<iostream>
  2. #include<cstring>
  3. using namespace std;
  4. const int maxn=100005;
  5. string s[maxn];
  6. struct node
  7. {
  8. bool f;
  9. node *next[26];
  10. node(){ f=0;memset(next,0,sizeof(next));}
  11. };
  12. node *root=new node();
  13. void Insert(string s)
  14. {
  15. node *p=root;
  16. for(int i=0;i<s.size();i++)
  17. {
  18. int id=s[i]-'a';
  19. if(p->next[id]==NULL) p->next[id]=new node();
  20. p=p->next[id];
  21. }
  22. p->f=1;
  23. }
  24. bool Find(string s)
  25. {
  26. if(s=="") return 0;
  27. node *p=root;
  28. for(int i=0;i<s.size();i++)
  29. {
  30. int id=s[i]-'a';
  31. p=p->next[id];
  32. if(p==0) return 0;
  33. }
  34. return p->f;
  35. }
  36. bool Query(string s)
  37. {
  38. node *p=root;
  39. for(int i=0;i<s.size()-1;i++)
  40. {
  41. int id=s[i]-'a';
  42. p=p->next[id];
  43. if(p==0) return 0;
  44. if(p->f&&Find(s.substr(i+1))) return 1;
  45. }
  46. return 0;
  47. }
  48. int main()
  49. {
  50. string str;
  51. int pos=0;
  52. while(cin>>str)
  53. {
  54. s[pos++]=str;
  55. Insert(str);
  56. // if(pos==6) break;
  57. }
  58. for(int i=0;i<pos;i++)
  59. if(Query(s[i])) cout<<s[i]<<endl;
  60. return 0;
  61. }

题意:给出斐波那契数列的前k位,k不超过40,找出最小的正整数n,满足F(n)的前k位与给定数的前k位相同,斐波那契数列的项数不超过100000。

解析:本题可以分为两步:

第一步就是预处理出100000项斐波那契数列的前40位,插入到字典树中。

第二步就是查询匹配求最小的n。

对于第一步,我们可以把斐波那契数列精确到50多位,然后只存40位即可,这样就防止进位的误差。在斐波那契数列加法过程中,我们只把它的前50多

位进行相加,不然存不下。

    
    
  1. #include <iostream>
  2. #include <string.h>
  3. #include <stdio.h>
  4. using namespace std;
  5. const int N=10;
  6. int f1[65],f2[65],f3[65];
  7. class Trie
  8. {
  9. public:
  10. int v;
  11. int flag;
  12. Trie *next[N];
  13. Trie()
  14. {
  15. v=-1;
  16. memset(next,NULL,sizeof(next));
  17. }
  18. };
  19. Trie *root;
  20. void Insert(char *S,int ans)
  21. {
  22. int len=strlen(S);
  23. Trie *p=root;
  24. for(int i=0;i<len;i++)
  25. {
  26. int id=S[i]-'0';
  27. if(p->next[id]==NULL)
  28. p->next[id]=new Trie();
  29. p=p->next[id];
  30. if(p->v<0) p->v=ans;
  31. }
  32. }
  33. int Find(char *S)
  34. {
  35. Trie *p=root;
  36. int count;
  37. int len=strlen(S);
  38. for(int i=0;i<len;i++)
  39. {
  40. int id=S[i]-'0';
  41. p=p->next[id];
  42. if(p==NULL) return -1;
  43. else count=p->v;
  44. }
  45. return count;
  46. }
  47. void Init()
  48. {
  49. int h;
  50. char str[65]="1";
  51. memset(f1,0,sizeof(f1));
  52. memset(f2,0,sizeof(f2));
  53. memset(f3,0,sizeof(f3));
  54. f1[0]=1;f2[0]=1;
  55. Insert(str,0);
  56. for(int i=2;i<100000;i++)
  57. {
  58. memset(str,0,sizeof(str));
  59. int r=0;
  60. for(int j=0;j<60;j++)
  61. {
  62. f3[j]=f1[j]+f2[j]+r;
  63. r=f3[j]/10;
  64. f3[j]%=10;
  65. }
  66. for(int j=59;j>=0;j--)
  67. if(f3[j])
  68. {
  69. h=j;
  70. break;
  71. }
  72. int k=0;
  73. for(int j=h;j>=0;j--)
  74. {
  75. str[k++]=f3[j]+'0';
  76. if(k>=40) break;
  77. }
  78. Insert(str,i);
  79. if(h>55)
  80. {
  81. for(int j=1;j<59;j++)
  82. f3[j-1]=f3[j];
  83. for(int j=1;j<59;j++)
  84. f2[j-1]=f2[j];
  85. }
  86. for(int j=0;j<60;j++)
  87. f1[j]=f2[j];
  88. for(int j=0;j<60;j++)
  89. f2[j]=f3[j];
  90. }
  91. }
  92. int main()
  93. {
  94. root=new Trie();
  95. Init();
  96. char str[105];
  97. int t,i,j,k=1;
  98. scanf("%d",&t);
  99. while(t--)
  100. {
  101. scanf("%s",str);
  102. printf("Case #%d: ",k++);
  103. int tmp=Find(str);
  104. printf("%d\n",tmp);
  105. }
  106. return 0;
  107. }


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值