第四周的题目是前两周的综合,综合在一个是KMP算法的思想,一个是树的这么一个数据结构。

题目 : Trie图

输入

每个输入文件有且仅有一组测试数据。

每个测试数据的第一行为一个整数N,表示河蟹词典的大小。

接下来的N行,每一行为一个由小写英文字母组成的河蟹词语。

接下来的一行,为一篇长度不超过M,由小写英文字母组成的文章。

对于60%的数据,所有河蟹词语的长度总和小于10, M<=10

对于80%的数据,所有河蟹词语的长度总和小于10^3, M<=10^3

对于100%的数据,所有河蟹词语的长度总和小于10^6, M<=10^6, N<=1000

输出

对于每组测试数据,输出一行"YES"或者"NO",表示文章中是否含有河蟹词语。

样例输入

6

aaabc

aaac

abcc

ac

bcd

cd

aaaaaaaaaaabaaadaaac

样例输出

YES

一开始我的思路是对每一个节点,每一个struct立面定义一个suffix指针,代表它的后缀节点,但是因为题目要不断地查找后缀节点,这样指针觉得麻烦,所以直接定义一个node[1000005],因为题目中已经说了最多的词语长度就是10^6。

不多说,直接上代码,代码中细说。

#include <iostream>
#include <cstring>
#include <queue>
using namespace std; #define len 1000000 char s[1000006];
char dir[1000006]; int node_count=0;//节点总数 struct Node {
int flag;//是否结束
int suffix;//node[p].suffix的值就直接代表它的后缀节点
int next[26];//这里的next是为构建树所用,即node[p].next['a']就代表当前节点经过字符'a'跳到哪一个节点中去
}node[len]; void init()
{
int count;
for(count =0;count<len;count++)
{
node[count].flag = 0;
node[count].suffix = 0;
for(int i=0;i<26;i++)
node[count].next[i]= 0;
}
} void Add_Trie(char *f_s)
{
int len_s = strlen(f_s);
int p=0,i; for(i=0;f_s[i];i++)
{
if(!node[p].next[f_s[i]-'a'] )
{
node[p].next[f_s[i]-'a']= ++node_count;
} p=node[p].next[f_s[i]-'a'];
}
node[p].flag = 1; } void Cal_Suffix()
{
queue<int> q;
/*这个队列我没想到,是看到其他人的代码才想到的
一开始我是循环了所有节点,结果就是处理的很乱,
有的处理了两遍。所以,实际上用queue的好处在于
能理清思路,这个节点进入队列,开始计算这个节点
后缀节点,顿时思路很清晰明了了。
其实后缀节点只是为了计算next[]数组时所用的工具。
因为next数组在树中一开始只是记录真正经过的节点,
现在要通过next数组来计算如果这时字符串与字典不
匹配的话,要跳到哪里去,实际上感觉这像是自动机
的内容*/
int p, i;
q.push(0);
while(!q.empty())
{
p = q.front();
q.pop(); if(node[node[p].suffix].flag ==1)
node[p].flag = 1;
for(i = 0; i < 26; i++)
if(node[p].next[i])//如果该节点有下一个节点
{
q.push(node[p].next[i]);//就把它放入到队列中
if(p)
node[node[p].next[i]].suffix = node[node[p].suffix].next[i];//如果不是起始节点,那么当前节点P的经过字符i下一个节点的后缀节点是P的后缀节点经过字符i后的节点
}
else
node[p].next[i] = node[node[p].suffix].next[i];//如果没有下一个节点,那么这时suffix发威了,就跳到当前节点P的后缀节点经过字符i的节点上去
}
} bool Search(char *f_s)
{
int len_f_s = strlen(f_s);
int count1=0,p=0; while(f_s[count1])
{
p=node[p].next[f_s[count1] - 'a'];
if(node[p].flag == 1)
{
return true;
}
count1++;
}
return false;
}
int main()
{
init(); int dir_count;
cin>>dir_count; while(dir_count--)
{
cin>>s;
Add_Trie(s);//添加到树种
} Cal_Suffix();//计算每个节点的后缀节点 cin>>dir;
if(Search(dir))//计算结果
cout<<"YES"<<endl;
else
cout<<"NO"<<endl; return 0;
}

整个程序第一点感受就是赋初值别乱赋,想清楚了在开始,一开始的suffix,next数组初值设置为-1,殊不知,可能那里一个取值(数组[-1]),程序就出错了。

第二点感受在memset函数的使用上,以后memset除了0,除了char型数组,用的话要小心谨慎。

第三点感受就是这道题看着复杂,但人家都有hint了。。。理清思路的话,不是很难。

最后一点感受就是 好像是拖得越久,记得越深。。。现在每次做题都能把焦点从算法转移到某一个函数用法或是数据结构上去,说明自己基础还是远远不够。STL中的vector、queue、list等 ,只是知道了其用法,根本没有完全掌握。

下次再编代码之前,要首先理清思路,设计好整个程序的数据结构,各个函数的用法,再去实现其具体功能,比现在这样上来就编然后就提交,再然后就是WA,再去找bug,改得最后面目全非的,思路逻辑混乱,几乎就是看正确答案才能编出来的这幅德行好多了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

HihoCoder第四周:Trie图的更多相关文章

  1. 【hihoCoder】1036 Trie图

    题目:http://hihocoder.com/problemset/problem/1036 给一个词典dict,词典中包含了一些单词words.要求判断给定的一个文本串text中是否包含这个字典中 ...

  2. 【hihoCoder 1036】Trie图

    看了一下简单的$Trie图$,调模板调啊调一连调了$2h$,最后发现$-'a'$打成$-'A'$了hhh,有种摔键盘的冲动. $Trie图$是$Trie树$上建立“前缀边”,不用再像在$Trie树$上 ...

  3. hiho一下 第二周&第四周:从Trie树到Trie图

    hihocoder #1014 题目地址:http://hihocoder.com/problemset/problem/1014 hihocoder #1036 题目地址: http://hihoc ...

  4. hihoCoder#1036 Trie图

    原题地址 看了这篇博文,总算是把Trie图弄明白了 Runtime Error了无数次,一直不知道为什么,于是写了个脚本生成了一组大数据,发现果然段错误了. 调试了一下午,总算闹明白了,为什么呢? 1 ...

  5. Trie 图

    时间限制:20000ms 单点时限:1000ms 内存限制:512MB 描述 前情回顾 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本 ...

  6. 【AC自动机&&Trie图】积累

    以前KMP和后缀系列(主要是后缀数组,后缀自动机),都刷了一定数量的题,但是对于AC自动机,却有些冷落,罪过. 但是我感觉,在蓝桥杯比赛中AC自动机出现的概率比后缀系列大,简单的会考匹配,稍难一点会考 ...

  7. 小菜鸟 菜谈 KMP->字典树->AC自动机->trie 图 (改进与不改进)

    本文的主要宗旨是总结自己看了大佬们对AC自动机和trie 图 的一些理解与看法.(前沿:本人水平有限,总结有误,希望大佬们可以指出) KMP分割线--------------------------- ...

  8. 【BZOJ-2938】病毒 Trie图 + 拓扑排序

    2938: [Poi2000]病毒 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 609  Solved: 318[Submit][Status][Di ...

  9. 字符串 --- KMP Eentend-Kmp 自动机 trie图 trie树 后缀树 后缀数组

    涉及到字符串的问题,无外乎这样一些算法和数据结构:自动机 KMP算法 Extend-KMP 后缀树 后缀数组 trie树 trie图及其应用.当然这些都是比较高级的数据结构和算法,而这里面最常用和最熟 ...

随机推荐

  1. vue中加载three.js的gltf模型

    vue中加载three.js的gltf模型 一.开始引入three.js相关插件.首先利用淘宝镜像,操作命令为: cnpm install three //npm install three也行 二. ...

  2. Verilog状态机

    以1011为例 代码如下: //1011(Meay型) module state1(clk,in,rst_n,out); input clk; input rst_n; input in; outpu ...

  3. UITextField的快速基本使用代码块

    概述 UITextField在界面中显示可编辑文本区域的对象. 您可以使用文本字段来使用屏幕键盘从用户收集基于文本的输入.键盘可以配置许多不同类型的输入,如纯文本,电子邮件,数字等等.文本字段使用目标 ...

  4. vue学习笔记:vue的认识与特点与获取

    Vue了解 Vue:读作 view Vue是一个渐进式框架 与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计. Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整 ...

  5. teraterm中log中加入时间戳

    步骤: 1.Setup->Additional settings->log->Timestamp(Local Time) 2.记录log.File->log(Teraterm. ...

  6. docker 的实践操作

    查看版本信息 [root@k8s-1 ~]# docker version Client: Version: 18.09.6 API version: 1.39 Go version: go1.10. ...

  7. 吴裕雄--天生自然PythonDjangoWeb企业开发:需求

    开发或者做一个项目,是要有一个需求过来的,而不是无缘无故的,启动一个项目,或者推动整个项目进行下一步迭代.这个需求可能是根据用户反馈增加的,可能是老板提出来的,也有可能是产品经理提出来的,但是无论是什 ...

  8. ES5中的this

    参考资料:>>> this的指向 在 ES5 中,其实 this 的指向,始终坚持一个原理: this 永远指向最后调用它的那个对象 下面我们来看一个最简单的例子:(例子均来自参考资 ...

  9. 夯实Java基础(二十三)——Java8新特征之Stream API

    1.Stream简介 Java8中除了引入了好用的Lambda表达式.Date API之外,另外还有一大亮点就是Stream API了,也是最值得所有Java开发人员学习的一个知识点,因为它的功能非常 ...

  10. Linux命令:route命令

    route显示或修改IP路由表 route -n:显示路由信息,使用数字格式显示,不反解地址到主机名 #route -n Kernel IP routing table Destination Gat ...