UVA12676 Inverting Huffman

简介: UVA12676 Inverting Huffman

UVA12676 Inverting Huffman


题目描述:

静态哈夫曼编码是一种主要用于文本压缩的编码算法。给定一个由 N 个不同字符组成的特定长度的文本,算法选择 N 个编码,每个不同的字符一个编码。使用这些编码压缩文本,当选择编码算法构建一个具有 N 个叶子的二叉树时,对于 N≥2,树的构建如下:


对文本中的每个不同字符,构建一个仅包含单个结点的树,并为其分配权值,权值与文本中该字符出现的次数一致。

构建一个包含上述 N 棵树的集合 s。

当 s 包含多于一棵树时:

(a) 选择最小的权值 t1∈s,并将其从 s 中删除;

(b) 选择最小的权值 t2∈s,并将其从 s 中删除;

(c) 构建一棵新树 t,t1 为其左子树,t2 为其右子树,并且 t 的权值为 t1、t2 权

值之和;

(d) 将 t 加入 s 集合。

返回保留在 s 中的唯一一棵树。

对于文本““abracadabra”,由上述过程生成的树,可以像下图左侧,其中每个内部结点编辑有子树根的权值。请注意获得的树也可以像下图右侧或其它,因为在步骤 3(a)、3(b)中,结合可能包含几个权值最小的树。

20210221130906747.jpg

对文本中的每个不同字符,其编码取决于最终树中从根到对应字符的叶子之间的路径,编码的长度是这条路径中的边数(与路径中的内部结点一致)。假设该算法构建的是左侧的树,“r”的代码长度为 3,“d”的代码长度为 4。

根据算法选择的 N 个代码的长度,找所有字符总数的最小值。

输入:

输入文件包含多个测试用例,每个测试用例如下所述:

第一行包含一个整数 N(2≤N≤50),表示文本中出现的不同字符数。

第二行包含 N 个整数 Li(1≤Li≤50,i=1,2,…,N),表示由 huffman 算法生成的不同字符的编码长度。

假设至少存在一棵上述算法构建的树,可以生成具有给定长度的编码。


输出:

对每个测试用例,输出一行,表示所有字符总数的最小值。


样例输入

2

1 1

4

2 2 2 2

10

8 2 4 7 5 1 6 9 3 9


样例输出

2

4

89


题解:

根据编码长度,推测最小字符数。

举例:

4

3 1 2 3

最长编码为 3,即最大深度为 3。

20210221131020376.jpg


算法设计:

(1) 每一层用一个深度数组 deep[]记录该层结点权值,该层每个结点的权值初始化

为 0,等待推测权值;

(2) 根据输入的编码长度算出最大长度即最大深度 maxd。

(3) 从最大深度 maxd 向上计算并推测,直到树根。开始时 temp=1;

⚫ i=maxd:第 i 层的结点权值如果为 0,则初始化为 temp(此时,temp=1)。

对第 i 层从小到大排序,然后将第 i 层每两个合并,权值放入上一层(i-1

层)。更新 temp 为第 i 层排序后的最后一个元素(最大元素)。

⚫ i=maxd-1:重复上述操作;

⚫ i=0:结束。输出第 0 层第一个元素。


解题思路

本题主要考察哈夫曼树的应用;

题目要求给出每个字符出现的长度,计算编码的最小长度.可以从后往前推,但要明白上一层的叶子结点值必须>=本层节点的最大值.最后一层值为1.然后依次往上推即可.最后根节点对应的权值便是编码的最小长度.


代码实现

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXSIZE = 60;
vector<long long> deep[MAXSIZE];
int n,x,maxd;
long long temp = 1;
int main()
{
  while (cin >> n)
  {
    for (int i = 0; i < n; i++)
    {
      cin >> x;
      deep[x].push_back(0);
      maxd = max(maxd, x);//求最大深度
    }
    for (int i = maxd; i > 0; i--)//从maxd向上推测
    {
      for (int j = 0; j < deep[i].size(); j++)//第i层初始化
      {
        if (!deep[i][j])
        {
          deep[i][j] = temp;
        }
      }
      sort(deep[i].begin(), deep[i].end());//排序
      for (int j = 0; j < deep[i].size(); j += 2)//两两合并
      {
        deep[i - 1].push_back(deep[i][j] + deep[i][j + 1]);//新生成的节点放到上一层
      }
      temp = *(deep[i].end() - 1);//更新temp  上一层叶子结点权值 >= 该层的最大值.
    }
    cout << *deep[0].begin() << endl;//输出最小长度.
    //更新数据
    for (int i = 0; i < MAXSIZE; i++)//数组初始化
    {
      deep[i].clear();
    }
    maxd = 0;
    temp = 1;
  }
  return 0;
}
相关文章
|
9月前
UVa11710 - Expensive subway(最小生成树)
UVa11710 - Expensive subway(最小生成树)
27 0
|
9月前
uva127 "Accordian" Patience
uva127 "Accordian" Patience
25 0
|
机器学习/深度学习 人工智能 Java
uva 548 Tree
点击打开链接uva 548 思路: 二叉树 分析: 1 题目给定一棵二叉树的中序序列和后序序列求这个二叉树里面,根节点到叶子节点的最短路径的叶子节点的值,如果有多条路径输出最小的叶子节点 2 题目说最多有10000个节点,但是由于题目所说...
1109 0
uva 1121 - Subsequence
点击打开链接uva 1121 思路:二分查找 分析: 1 题目要求找到一个最短的子序列长度并且这个子序列的和大于等于给定的s 2 如果按照常规的做法枚举起点和终点的话肯定是会超时的。
910 0
zoj 2913 BFS
//zoj 2913 BFS // 从每条线路上的每个地区出发进行BFS遍历, // 统计每条线路上每个地区到其他地区最短距离中的最大值,求出所有最大值中的最小值。 #include&lt;stdio.h&gt; #include&lt;queue&gt; #include&lt;string.h&gt; using namespace std; #define MAX 10000 #de
940 0
zoj 1649 BFS
// zoj 1649 #include&lt;stdio.h&gt; #include&lt;queue&gt; #include&lt;string.h&gt; using namespace std; #define MAXN 200 #define INF 1000000 struct point { int x,y; int step,time; }; queue
1046 0