#1117. 编码 ( 字典树版 ) 题解分析
【问题描述】
我们准备根据一份文本编码表对一篇文本进行压缩。编码表的每一项包含两个部分:要编码的字符串和对应的编码。编码是二进制的01串,用来替代文本中相应的字符串以实现压缩编码的目的。这些01串不一定是等长的。文本压缩所要考虑的问题是对给定的文本和编码表,求出能令整个文本的编码最短的二进制串的长度。例如文本:abcdef
编码表
a | abc | abcd |bcd|def|ef
01 | 0 | 1011 |1 |10 |11
下面有3种不同的方式进行编码:
方式1:长度为5
a bcd ef
01 1 11
方式2:长度为3
abc def
0 10
方式3:长度为6
abcd ef
1011 11
很明显,方式2长度最短,你的任务是找出编码后文本的最短长度,若不能进行编码,则输出0.
【输入格式】
输入可能包含多个文本压缩问题。
第一行是一个整数n,表示有n个文本压缩问题。(n≤10)
每个文本压缩问题的描述第一行是要压缩的文本(不超过210个字符),接下来是编码表,每项一行,不超过100项,只包含小写字母,外侧有小括号。
【输出格式】
对应每个文本压缩问题,每行输出一个最小长度。
【输入输出样例】
输入样例:
2
abcdef
(a,01)
(abc,0)
(abcd,1011)
(bcd,1)
(def,10)
(ef,11)
aa
(a,1)
(ab,10)
输出样例:
3
2
分割线君又来调皮了 _ (:з」∠)_
赛后和老师讨论了一下这道 t ,发现虽说是有点麻烦,但是也不是很坑[ 远没有t1坑 _ ( :з」∠) _ ] , 如果用字典树优化的话(其实不优化也能A过去,而且优不优化都是0ms,可以说数据水么?)可以降降时间复杂度,但是我又测了一下效率之后发现可能这么做丝毫没有优化时间复杂度(原因:原题目中的编码表项数太小+原数据太水),如果说编码表项数的上线是一万(1e4)的话那么用字典树做优化很明显…不然随随便便枚举编码表然后加个dp这道题也能水过去[PS: 测试点只有5个]
但是字典树貌似也有个缺陷就是要开较大的数组(这道题在数据水的情况下我轻松就能在字典树210个节点的情况下A了,还是数据水…),最最最最关键的就是要开多大的数组还很难算,本题数据贱的话貌似要2X1e4个节点的样子(最坏情况),如上所说如果说编码表项数是1万的话就是2X1e6的样子.(所以说这题数据真心水,210个节点也就这么划过去了)
然后这题我就A了20。。。TAT 所以第一个程序的源代码我就不放了 (还有一个原因就是我懒)_ (:з」∠)_
那么这道题既然说了字典树就用字典树讲吧,顺便让童鞋们(也和我一起)科普科普字典树这玩意儿。另外,本篇blog不会详细讲字典树的内容,所以请童鞋们自行百度。
然后我就先简要概括一下字典树这(辣鸡)玩意儿吧:
Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树。与二叉查找树不同,Trie树的键不是直接保存对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。搜索字典项目的方法为:1. 从根结点开始一次搜索;2. 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;3. 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。4. 迭代过程……(我也搞不懂是神马玩意儿,反正在这里应该就是下标一类的玩意儿了)5. 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
顺便盗个图
emm…都是借鉴来的介绍、、、其他关于字典树的东西这里就不赘述了,如有兴趣自行百度。
好了,上代码吧。(对了,程序里的主函数中有许多字符串的函数,如有不懂的可以去搜一下,顺便当做复习)
include<bits/stdc++.h> //运用字典树来处理查找问题
using namespace std;
int n,k,h,rt;
string s,p;
int len,v,dp[210]; //dp[i]表示在做到i号位置时付出的最小价值
int trie[210][26]; //trie[i][j]表示在第i号节点的后继中,有无j字母,//如果有,那么这个后继的编号则记录在trie[i][j]中
int val[210]; //val[i]表示在字典树的第i号节点上有无完整字符串//如果有,那么这个字符串的价值就记录在val[i]中 void work()
{len=s.length(); //len赋值为s的(有效)长度s=" "+s; //s前加个空格方便操作for(int i=1;i<=len;++i) //从前往后做dp{rt=0; //从根节点开始查找for(int j=i;j>=1;--j)//一直往前找,按照要压缩的文本字符串查找是否已有此字符串编码{int x=s[j]-'a';if(!trie[rt][x]) break; //查无此字符串,则直接退出
//(找不到当前节点的话后面也不用再找下去了,相当于树到这里已经断了,
//字符串在字典树中已经不可能匹配了) rt=trie[rt][x]; //获得该节点的后继 x 字母的节点编号if(val[rt]!=0x3f3f3f3f && dp[j-1]!=0x3f3f3f3f)dp[i]=min(dp[i] , dp[j-1]+val[rt]); //取最小值}}cout<< (dp[len]==0x3f3f3f3f ? 0 : dp[len]) <<endl; //直接输出dp[len]
}int main()
{ios::sync_with_stdio(false); //输入输出流的优化,你懂的 (o^.^o)cin>>n>>s;
while(n--)
{k=0; h=0;memset(trie , 0 , sizeof(trie));memset(val , 0x3f , sizeof(val));memset(dp , 0x3f , sizeof(dp)); dp[0]=0; //将整个dp数组赋值inf之后,//要把dp[0]赋为0,作为dp的基础while(cin>>p && p[0]=='('){ //这里就是对读入的数据是否是编码表项len=p.find(',')-p.find('(')-1; // 运用字符串函数得到p的长度 和 价值v=p.find(')')-p.find(',')-1;p=p.substr(1,len); //取出真正的 编码rt=0;for(int i=len-1;i>=0;--i)//这里从后往前存点,因为等会儿的dp也是从后往前匹配的{int x=p[i]-'a'; //得到的x代表了26个字母之一if(!trie[rt][x]) //如果尚未有点就自己建一个点trie[rt][x]=++h;rt=trie[rt][x]; //然后rt指向当前节点的后继 x 字母}val[rt]=min(val[rt] , v); //最终在树的字符串底端}work();s=p; //之前读入的非编码表项其实是要压缩的文本,直接赋值给s
}return 0;
}
ok,这就是字典树的做法了。希望童鞋们看完后能有所收获 QAQ
另外附上我的实验结果(十组数据时):
编码表项数\优化方法 | 无优化线性枚举 | 区间预处理 | 字典树优化 |
---|---|---|---|
100 | 70ms | 40ms | 50ms |
1000 | 350ms | 90ms | 60ms |
10000 | 3200ms | 570ms | 240ms |
然后……再见 _ (:з」∠)_
转载于:https://www.cnblogs.com/Judge/p/9383040.html
#1117. 编码 ( 字典树版 ) 题解分析相关推荐
- newcoder 筱玛的迷阵探险(搜索 + 01字典树)题解
题目描述 筱玛是个快乐的男孩子. 寒假终于到了,筱玛决定请他的朋友们一起来玩迷阵探险. 迷阵可以看做一个n×nn×n的矩阵A,每个格子上有一个有一个数Ai,j. 入口在左上角的(1,1)处,出口在右下 ...
- 蒟蒻君的刷题日记Day12(线段树专题T4):P8082 [COCI2011-2012#4] KEKS 线段树版题解
解题思路 看题解区的大佬们用的都是单调栈,本蒟蒻献上一篇线段树题解. 整个数最大,首先位数是确定的,则肯定优先考虑高位大小. 大体思路就是从前向后依次求出每一位的值(好像是废话). 对于第 iii 位 ...
- 词频分析--字典树的应用
词频分析–字典树的应用 字典树又称单词查找树,Trie树,前缀树,是一种树形结构,是一种哈希树的变种. 典型应用是用于统计,排序和保存大量的字符串所以经常被搜索引擎系统用于文本词频统计. 它的优点是: ...
- HDU-1671 Phone List 暴力版 + 字典树
该题就是判定一个所给定串集中是否有某些串是另外一些串的前缀串的问题.字典树的话很好办只要判定在构建一个串的路径中是否已经有的节点被标记(此处有串结尾)和如果一个串在该处结尾,那么是否它的的孩子都为空. ...
- 字典树 —— 字符串分析算法
这里我们继续来编程训练,在<前端进阶>这个系列里面我们已经讲过一些字符串的算法了.然后这篇文章我们就来一起学习,剩下的几个字符串中比较细节的算法. 字符串分析算法 在开始之前我们先来看看字 ...
- 实体知识+字典树辅助jieba的分词(并对三国演义进行简单分析)
在做中文NLP的时候,分词可谓是基础中的基础.然而这个基础部分的内容直到今天还是让人不省心,在实际应用中[尤其是在人名等实体的识别上]总是显得漏洞百出.下面以python上比较流行的一个中文分词库ji ...
- [(可持久化)字典树 优化建图][2-SAT] LOJ#6036. 雅礼集训 2017 Day4. 编码
老早以前的坑了 貌似好多地方都有这个题 因为每个串都只有一个问号,问号可取0可取1,这就是一个经典的2-SAT模型 但是直接做的话,边数是n2n^2级别的,不过因为是01串,可以用可持久化字典树优化建 ...
- 字典树实现_【Leetcode每日打卡】单词的压缩编码 Trie(字典树)入门
一.前言(鸡汤(一段废..话..可以跳过啦)) 同学们好!没想到我这个小小的公众号破千粉啦,对于大佬们而言或许不值一提,但是对我而言是一个莫大的鼓舞!更加坚定了我持续输出优质内容的决心.希望我们都能每 ...
- 数据结构:字典树的基本使用
概述: 说来也奇怪,最近碰到的很多问题都需要用字典树来解决,索性就来研究一番.在这篇博客中,我会通过一些实例来讲解一下字典树的一些基本使用.例如:创建.添加.查找.按字典序排序.按数值大小进行排序(对 ...
最新文章
- 常量元素记忆口诀_化学口诀表:帮助学生加深记忆提高解题正确率
- Java在linux新建png_教你如何使用libpng显示PNG图片
- 7年前轰动全球的Science论文,被发现可能搞错了
- peleenet测试
- Qt修炼手册4_信号与槽
- python读取xlsx文件pandas_用Python的pandas框架操作Excel文件中的数据教程
- mysql 搜索不等于_Mysql索引分类
- [转]苦逼男和女神之间的经典对话,亲身经历过的有木有啊,必须转。。。
- 2018-04-28
- 利用 Google Chart API 生成二维码大小不一致
- PPT处理控件Aspose.Slides功能演示:使用 Java 在 PowerPoint 中创建和操作表格
- Java标识符、关键字、运算符
- Linux命令之ss命令
- 显示虚拟按钮Menu键
- 尤雨溪Vue登榜GitHub之路看似不难
- 银河麒麟系统QtCreator不能切换中文输入法问题解决
- XV6源代码阅读-虚拟内存管理
- 新学期可以制定目标计划并提醒的便签软件是哪款?
- Java开发入门教程!java开发架构师职责
- 深度学习知识库精华+图谱一览
热门文章
- 绝对简单,就是将我自己的工作量估算乘2!!!
- 黄聪: Bootstrap之Form表单验证神器: BootstrapValidator(转)
- RPM方式安装MySQL5.6和windows下安装mysql解压版
- windows 加域
- python 访问 zookeeper
- mstsc /console 远程命令
- AndroidStudio设置不自动弹出 Documentation 窗口
- ScrollView’s handy trick--android:fillViewport=quot;truequot;
- C++中函数模板的用法详细解析
- Elastic Job入门(1) - 简介