感觉不把这个Trie理解一下,AC自动机的代码看起来有点费劲。

这里代码的学习仿照训练指南209页。

这里如果只是查询单词,感觉用map更好,但是如果查前缀,还是用Trie。

1、Trie查询前缀字符串是否存在。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define mst(s,v) memset(s, v, sizeof(s));
  4. const int maxnode = ;
  5. const int sigma_size = ;
  6. //字母表为全体小写字母的Trie
  7. struct Trie{
  8. int ch[maxnode][sigma_size];
  9. int val[maxnode];
  10. int sz; //结点总数
  11. Trie(){ sz=; mst(ch[], ); mst(val, ); } //初始时只有一个根节点
  12. int idx(char c) { return c-'a'; }
  13. //插入字符串s,附加信息为v。v!=0(0代表本身不是单词结点)
  14. void insert(char *s, int v){
  15. int u = , n = strlen(s);
  16. for(int i=; i<n; i++){
  17. int c = idx(s[i]);
  18. if(!ch[u][c]){ //结点不存在
  19. memset(ch[sz], , sizeof(ch[sz]));
  20. val[sz] = ; //中间结点的附加信息为0
  21. ch[u][c] = sz++;
  22. }
  23. u = ch[u][c];
  24. }
  25. val[u] = v; //字符串的最后一个字符的附加信息
  26. //标记在末结点,查询整个单词时有用
  27. }
  28. bool find(char *s){
  29. int u = , len = strlen(s);
  30. for(int i=; i<len; i++){
  31. int c = idx(s[i]);
  32. if(!ch[u][c]) return false;
  33. u = ch[u][c];
  34. }
  35. return true; //查询整个单词时 return val[u]
  36. }
  37. }tree;
  38. int main(){
  39. freopen("in.txt", "r", stdin);
  40. int n, m;
  41. cin >> n >> m;
  42. char tmp[];
  43. for(int i=; i<n; i++){
  44. cin >> tmp;
  45. cout << tmp << endl;
  46. tree.insert(tmp, );
  47. }
  48. for(int i=; i<m; i++){
  49. cin >> tmp;
  50. cout << endl << tmp << endl;
  51. if(tree.find(tmp)) cout << "Y" << endl;
  52. else cout << "N" << endl;
  53. }
  54. return ;
  55. }
  56. /*
  57. 6 2
  58. shex
  59. shexy
  60. yasherhs
  61. say
  62. shrxy
  63. sher
  64. yasherhs
  65. she
  66. */

2、Trie查询前缀个数

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define mst(s,v) memset(s, v, sizeof(s));
  4. const int maxnode = ;
  5. const int sigma_size = ;
  6. //可以查找前缀,也可以查找单词(map)
  7. struct Trie{
  8. int ch[maxnode][sigma_size];
  9. int sum[maxnode];
  10. int sz; //结点总数
  11. Trie(){ sz=; mst(ch[], ); mst(sum, ); }
  12. int idx(char c) { return c-'a'; }
  13. //插入字符串s,附加信息为v。v!=0(0代表本身不是单词结点)
  14. void insert(char *s){
  15. int u = , n = strlen(s);
  16. for(int i=; i<n; i++){
  17. int c = idx(s[i]);
  18. if(!ch[u][c]){ //结点不存在
  19. memset(ch[sz], , sizeof(ch[sz]));
  20. ch[u][c] = sz++;
  21. }
  22. sum[ch[u][c]]++;
  23. u = ch[u][c];
  24. }
  25. }
  26. int find(char *s){
  27. int u = , len = strlen(s);
  28. for(int i=; i<len; i++){
  29. int c = idx(s[i]);
  30. if(!ch[u][c]) return ;
  31. u = ch[u][c];
  32. }
  33. return sum[u];
  34. }
  35. }tree;
  36. int main(){
  37. freopen("in.txt", "r", stdin);
  38. int n, m;
  39. cin >> n >> m;
  40. char tmp[];
  41. for(int i=; i<n; i++){
  42. cin >> tmp;
  43. tree.insert(tmp);
  44. }
  45. for(int i=; i<m; i++){
  46. cin >> tmp;
  47. cout << tmp << endl;
  48. cout << tree.find(tmp) << endl;
  49. }
  50. return ;
  51. }

3、用指针理解Trie

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define mst(s,v) memset(s, v, sizeof(s));
  4. const int sigma_size = ;
  5. struct node{
  6. int count;
  7. node * next[];
  8. }*root;
  9. int idx(char c){ return c-'a'; }
  10. node* build(){
  11. node* k = new(node);
  12. k->count = ;
  13. mst(k->next , );
  14. return k;
  15. }
  16. void insert(char* s){
  17. node* r = root;
  18. char* word = s;
  19. while(*word){
  20. int c = idx(*word);
  21. if(r->next[c] == NULL) r->next[c] = build();
  22. r = r->next[c];
  23. r->count++;
  24. word++;
  25. }
  26. }
  27. int find(char* s){
  28. node* r = root;
  29. char* word = s;
  30. while(*word){
  31. int c = idx(*word);
  32. r = r->next[c];
  33. if(r==NULL) return ;
  34. word++;
  35. }
  36. return r->count;
  37. }
  38. int main(){
  39. freopen("in.txt", "r", stdin);
  40. int n, m;
  41. cin >> n >> m;
  42. char tmp[];
  43. root = build();
  44. for(int i=; i<n; i++){
  45. cin >> tmp;
  46. insert(tmp);
  47. }
  48. for(int i=; i<m; i++){
  49. cin >> tmp;
  50. cout << tmp << endl;
  51. cout << find(tmp) << endl;
  52. }
  53. return ;
  54. }

Trie灵活的地方是在插入时对点的属性的更新,以及查询时与其他算法的结合。

这里将AC自动机summer-work那里的C - L语言拿过来,感受在查询变化的一些思路。

题意:n(1,20)模式串(可以有包含关系(这就决定了不能贪心)),m(1,20)文本串,对每个文本串,n个模式串最多可以组成的最长前缀的位置。

这题就是在find()上思考解法,正解应该是dp[i]是否能理解前i个单词,这里因为是学习Trie,所以就暴力吧(感觉自己太水)。

这里总结一个套路,因为是单词而非前缀,所以insert()时点的属性是val=1。

为了创造vis(是否理解前i个单词)的边界条件vis[0]=v(明显可以识别),所以这里scanf(s+1),即遍历时从i+1开始。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define mst(s,v) memset(s, v, sizeof(s));
  4. const int maxnode = ;
  5. const int sigma_size = ;
  6. const int maxlen = 1e6 + 5e4;
  7. int dp[maxlen];
  8. struct Trie{
  9. int ch[maxnode][sigma_size];
  10. int val[maxlen];
  11. int sz;
  12. Trie(){ sz=; }
  13. inline int idx(char c) { return c-'a'; }
  14. inline void insert(char *s){
  15. int u = , n = strlen(s);
  16. for(int i=; i<n; i++){
  17. int c = idx(s[i]);
  18. if(!ch[u][c]){
  19. ch[u][c] = sz++;
  20. }
  21. u = ch[u][c];
  22. }
  23. val[u] = ; //标记单词
  24. }
  25. inline int find(char *s, int v){
  26. int u = , len = strlen(s), ans = ;
  27. dp[] = v; //标记能够被识别的前缀位置
  28. for(int i=; i<len; i++){
  29. if(dp[i] == v){
  30. u = ;
  31. for(int j=i+; j<len; j++){
  32. int c = idx(s[j]);
  33. if(!ch[u][c]) break;
  34. //cout<<"u = "<<u<<" v = "<<v<<" s[j] = "<<s[j]<<endl;
  35. u = ch[u][c];
  36. if(val[u]){ //找到单词的前缀
  37. ans = max(ans, j);
  38. dp[j] = v; //标记位置
  39. }
  40. }
  41. }
  42. }
  43. return ans;
  44. }
  45. }tree;
  46. char tmp[maxlen];
  47. int main(){
  48. // freopen("in.txt", "r", stdin);
  49. int n, m;
  50. scanf("%d%d", &n, &m);
  51. for(int i=; i<n; i++){
  52. scanf("%s", tmp);
  53. tree.insert(tmp);
  54. }
  55. for(int i=; i<=m; i++){
  56. scanf("%s", tmp+);
  57. printf("%d\n", tree.find(tmp, i));
  58. }
  59. return ;
  60. }

Trie代码学习的更多相关文章

  1. u-boot代码学习内容

    前言  u-boot代码庞大,不可能全部细读,只能有选择的读部分代码.在读代码之前,根据韦东山教材,关于代码学习内容和深度做以下预先划定. 一.Makefile.mkconfig.config.mk等 ...

  2. Objective-C代码学习大纲(3)

    Objective-C代码学习大纲(3) 2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍 ...

  3. ORB-SLAM2 论文&代码学习 ——Tracking 线程

    本文要点: ORB-SLAM2 Tracking 线程 论文内容介绍 ORB-SLAM2 Tracking 线程 代码结构介绍 写在前面 上一篇文章中我们已经对 ORB-SLAM2 系统有了一个概览性 ...

  4. ORB-SLAM2 论文&代码学习 —— 单目初始化

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...

  5. ORB-SLAM2 论文&代码学习 —— LocalMapping 线程

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12360913.html 本文要点: ORB-SLAM2 Local ...

  6. Learning Memory-guided Normality代码学习笔记

    Learning Memory-guided Normality代码学习笔记 记忆模块核心 Memory部分的核心在于以下定义Memory类的部分. class Memory(nn.Module): ...

  7. 3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习

    3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习 Hello小崔 ​ 华为技术有限公司 Linux内核开发 2 人赞同了该文章 LTP代码学习方法主要介绍两个步骤, ...

  8. Apollo代码学习(七)—MPC与LQR比较

    前言 Apollo中用到了PID.MPC和LQR三种控制器,其中,MPC和LQR控制器在状态方程的形式.状态变量的形式.目标函数的形式等有诸多相似之处,因此结合自己目前了解到的信息,将两者进行一定的比 ...

  9. Dagger2 生成代码学习

    接上一篇文章介绍了Dagger2的初步使用,相信刚接触的人会觉得很奇怪,怎么会有很多自己没有定义的代码出现,为什么Component的创建方式是那样的.为了搞清楚这些东西,我们需要查看一下Dagger ...

随机推荐

  1. Launcher类源码分析

    基于上一次获取系统类加载器这块进行分析: 关于这个方法的javadoc在之前已经阅读过了,不过这里再来仔细阅读一下加深印象: 这里有一个非常重要的概念:上下文类加载器: 它的作用非常之大,在后面会详细 ...

  2. P1361 小M的作物 最小割理解

    如果没有组合效益的存在 我们直接每个点两部分的最大值即可 换成网络流模型来看 即把S点看作是A田 把T点看作是B田 每种作物看作一个点 分别连边(S,i,A[i]) (i,T,B[i]) 最后图中所有 ...

  3. WebRtc的一些基本概念

    GCC:Google Congestion Control,谷歌提出的拥塞控制算法 REMB:Receiver Estimated Maximum Bitrate,  接收端最大接收码率估测,接收端会 ...

  4. 通过自动回复机器人学Mybatis---基础版

    第1章 案例简介 介绍要实现的案例情况,后面会通过这个案例来学习 Mybatis 第2章 实战第一部----黎明前的黑暗 在没有 Mybatis 的情况下,使用 Jsp + Servlet + Jdb ...

  5. 上传时excel类型accept的MIMI类型

    1.excel文件类型 accept='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/v ...

  6. dcm4che-core导包失败! mvn pom文件导包总是失败

    原因可能是所导的包不在共有项目中,可能在个人项目中,需要添加远程仓库 <!--远程仓库部署--><repositories> <repository> <id ...

  7. STMStudio-stm32软件的应用笔记

    上次编写中,已经提到该软件的功能了,可以增加调试手段. 编译出axf文件-keil和out文件-iar,注意keil在output文件名是,不能有"."既NL_ZKTP3_V1.0 ...

  8. 适配器模式(Adapter)---结构型

    1 基础知识 定义:将一个类的接口(被适配者)转换成客户期望的另一个接口(目标).特征:使原本接口不兼容的类可以一起工作. 本质:转换匹配,复用功能.把不兼容的接口转换为客户端期望的样子从而实现功能的 ...

  9. 解决蓝牙鼠标在 Ubuntu 中单位时间内断开的问题

    1 查询你的鼠标的蓝牙地址 1.1 如:E1:DE:02:05:5E:F5 2 将查询到的设备地址写入配置文件 /etc/bluetooth/main.conf # Use vendor id sou ...

  10. vue中前进刷新、后退缓存用户浏览数据和浏览位置的实践

    vue中前进刷新.后退缓存用户浏览数据和浏览位置的实践 2018年07月07日 11:58:40 大灰狼的小绵羊哥哥 阅读数:4492   vue中,我们所要实现的一个场景就是: 1.搜索页面==&g ...