第四周的题目是前两周的综合,综合在一个是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. python学习 —— 获取系统运行情况信息并在Linux下设置定时运行python脚本

    代码: # -*- coding:utf-8 -*- from psutil import * def cpu_usage_rate(): for i, j in zip(range(1, cpu_c ...

  2. Lucene的初步了解和学习

    Lucene的学习一,什么是全文检索 1.数据的分类 1.结构化数据 格式固定,长度固定,数据类型固定. 例如:数据库中的数据: 2.非结构化数据 word文档,pdf文档,邮件,html,txt 格 ...

  3. spark-调节executor堆外内存

    什么时候需要调节Executor的堆外内存大小? 当出现一下异常时: shuffle file cannot find,executor lost.task lost,out of memory 出现 ...

  4. Python 中命令行参数解析工具 docopt 安装和应用

    什么是 docopt? 1.docopt 是一种 Python 编写的命令行执行脚本的交互语言. 它是一种语言! 它是一种语言! 它是一种语言! 2.使用这种语言可以在自己的脚本中,添加一些规则限制. ...

  5. Kafka-JavaAPI(Producer And Consumer)

    Kafka--JAVA API(Producer和Consumer) Kafka 版本2.11-0.9.0.0 producer package com.yzy.spark.kafka; import ...

  6. LDAP-轻量级目录访问协议(统一认证)

    概念 LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP. 参考资料 LDAP概念和原理介绍 我花了一个五一终于搞懂 ...

  7. 3_05_MSSQL课程_Ado.Net_DataSet数据集

    //创建一个内存的数据集 DataSet ds=new DataSet("LJK"); //创建一张内存表 DataTable dt01=new DataTable("d ...

  8. C12Test5 record

  9. Codeforces 601A:The Two Routes 宽搜最短路径

    A. The Two Routes time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  10. vue + element ui table表格二次封装 常用功能

    因为在做后台管理项目的时候用到了大量的表格, 且功能大多相同,因此封装了一些常用的功能, 方便多次复用. 组件封装代码: <template> <el-table :data=&qu ...