哈夫曼编码这个词相信大家都不陌生,它是一种给字符编码的工具,发明他的人是美国的哈夫曼大叔,这个编码是用来压缩文件的,他要满足的是:
1.每个字符的编码中只含数字0,1;
2.每一个字符的编码都不是另一个字符的前缀(这样才保证输入的编码无歧义)
3.尽可能保证数量少(公式:每一个字符的频率*编码长度之和)
为了更好地满足这三个条件,我们创造出了一个以树和集合为基础的算法,就叫哈夫曼算法;
哈夫曼算法先是定义多个子树,有多少个字符就定义多少个树,这些树刚开始时都存于一个集合中,每一步把当前森林中频率最小的两棵子树合并为一棵子树 ,原始树作为子节点或子树,他的父亲的权值就是两个子节点的权值和,这可子树只能是二叉树,这一棵新树也存放与集合中,并代替掉了刚刚的两棵子树,这棵新树的频率就是那两棵子树的频率和…以此类推,重复操作。最后得到的树一定满足每个非叶节点恰好有两个子节点(因为编码只有0和1).
下面是此树的构造过程
注意:每两个子树合并为一个时,一定要添加父节点,不能直接将其中一个子树作为其父节点。
构造出树后,我们把每一条边都标上数值,保证每一个非叶节点的两个儿子的边有一个是0.有一个是1,这样才不会出现重复。
哈夫曼编码的计算过程:
刚才说了,我们要尽可能让哈夫曼编码的值小,这也是为什么要用最小的权值子树作为子树,这样可以让深度越深的字符权值越小,那么,哈夫曼编码的计算过程为:每个字符权值*长度之和。
应用:
[NOI2015] 荷马史诗
题目背景
追逐影子的人,自己就是影子 —— 荷马
题目描述
Allison 最近迷上了文学。她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的《荷马史诗》。但是由《奥德赛》和《伊利亚特》 组成的鸿篇巨制《荷马史诗》实在是太长了,Allison 想通过一种编码方式使得它变得短一些。
一部《荷马史诗》中有 nnn 种不同的单词,从 111 到 nnn 进行编号。其中第 iii 种单词出现的总次数为 wiw_iwi。Allison 想要用 kkk 进制串 sis_isi 来替换第 iii 种单词,使得其满足如下要求:
对于任意的 1≤i,j≤n1\leq i, j\leq n1≤i,j≤n ,i≠ji\ne ji=j ,都有:sis_isi 不是 sjs_jsj 的前缀。
现在 Allison 想要知道,如何选择 sis_isi,才能使替换以后得到的新的《荷马史诗》长度最小。在确保总长度最小的情况下,Allison 还想知道最长的 sis_isi 的最短长度是多少?
一个字符串被称为 kkk 进制字符串,当且仅当它的每个字符是 000 到 k−1k-1k−1 之间(包括 000 和 k−1k-1k−1 )的整数。
字符串 str1str1str1 被称为字符串 str2str2str2 的前缀,当且仅当:存在 1≤t≤m1 \leq t\leq m1≤t≤m ,使得 str1=str2[1..t]str1 = str2[1..t]str1=str2[1..t]。其中,mmm 是字符串 str2str2str2 的长度,str2[1..t]str2[1..t]str2[1..t] 表示 str2str2str2 的前 ttt 个字符组成的字符串。
输入格式
输入的第 111 行包含 222 个正整数 n,kn, kn,k ,中间用单个空格隔开,表示共有 nnn 种单词,需要使用 kkk 进制字符串进行替换。
接下来 nnn 行,第 i+1i + 1