转化为树
元前缀码的码长满足克拉夫特不等式 ,反之亦然。将长度排序,逐层把未使用的位置扩展成 个子位置,再放置当前层所需的叶子,即可得到对应的树。
因此,问题等价于构造一棵每个内部结点至多有 个孩子的树,使叶子权值与深度乘积之和最小。权值为 的输入元素也是实际叶子,不能删除。
哈夫曼合并
时输出 。否则,每个内部结点恰有 个孩子的树,其叶子数模 余 。补充
个权值为零的虚拟叶子。该操作不改变最优值:去掉最优树中的单子结点,并将未满的内部结点合并整理到最深处,只保留一个未满结点。把叶子向根移动不会增加非负权值的总代价。补满剩余位置恰好需要 个虚拟叶子。
通过交换较浅的轻叶子和较深的重叶子,可知存在一个最优解,使最小的 个权值对应的叶子位于最深层且拥有同一父结点。将它们缩成一个权值等于总和的叶子,原代价等于缩点后的代价加上这个总和。不断执行此操作即为 元哈夫曼算法。
实现时不必建立虚拟叶子。第一次合并
个实际结点,之后每次合并 个结点即可。 时有 ;当 能被 整除时,第一次也必须合并 个。
用最小堆选取结点,记录新结点为所取结点的父结点。父结点编号总是较大,因此按编号逆序计算深度,无需递归。按原输入顺序输出叶子深度。
内部结点至多有 个且每个至少有两个孩子,所以深度至多为 。时间复杂度为 ,空间复杂度为 。合并权值不超过 ;令所有深度等于 可得可行解,所以最优代价不超过 。有符号 位整数足够,无需直接计算 。
子任务 1 可将权值降序排序,再枚举取值为 至 的非递减深度序列,共 个。交换论证保证其中存在最优解。每个序列用 检查,总复杂度为 。子任务 2 使用二元哈夫曼算法,每次合并最小的两个权值,复杂度为 。
检查克拉夫特不等式时,从深度零的一个空位开始,扣除本层叶子数,再将剩余空位乘以 。需要的叶子数超过空位数则不合法。空位数可截断至 ,避免大整数,因为总共只有 个叶子。检查总代价时,以最优值作为剩余预算,在乘法前先用除法判断是否超出预算,避免错误输出造成溢出。
Solution written by GPT6