基本策略与霍夫曼编码一致。
考虑这样一种二叉树,根节点的值为空串,表示比特串的起始,其它所有节点的值均为0或1,可以规定若当前节点是其父节点的左子节点,则其值为0,否则值为1。
每一条从根节点到每一个叶节点的路径都唯一对应一个比特串,n元无前缀编码就可以按此方式形成一颗有n个叶节点的二叉树,例如题面中的六元无前缀编码对应二叉树:
为叙述方便,以下行文中不区分n元无前缀编码及其所对应的二叉树。
用表示一个n元无前缀编码,并用表示编码的花费。
记为中的编码的最大花费,记为中的编码的总花费。
令为最大花费不超过i的情况下的最多的编码数,即
记为满足上述要求、且总费用最低的树,注意由此定义可知这样的树是唯一的。
对而言,有初值,以及递推式
这是因为由最大性可以分别在的所有编码前添加一位和的所有编码前添加一位,再将两者合并来得到。
再令
则有初值(注意一元无前缀编码中总费用最低的是空树),再由的递推构造可得
设m是满足中最大的数,要计算,还需在中再添加条编码。
由叶节点数的最大性可知只能扩展那些费用不小于的叶节点。
在这样的叶节点下添加两个子节点,相当于在中先移除(),再添加和,因此总费用增加。
为使扩展后的总费用最低,应按k的值从大到小开始扩展,实现中经计算可以验证费用为的节点数超过个,因此只需扩展这一种类型的节点即可。
最后结果为
target=10**9
c=[1,1,1,1]
s=[0,0,0,0]
while c[-1]<=target:
s.append(s[-1]+s[-4]+c[-1]+4*c[-4])
c.append(c[-1]+c[-4])
print (target-c[-2])*len(c)+s[-2]
|