首页 > 其他分享 >哈夫曼树

哈夫曼树

时间:2022-10-28 22:12:38浏览次数:37  
标签:编码 le 哈夫曼 10 text 样例 dp

题目描述

哈夫曼树常用于解决最优编码问题:即给定若干种不同字符在文本中的出现次数(频率),试为每个字符给出一个 01 串作为编码,使得 $\text{频率}\times\text{码长}$ 之和最小,且没有任何一个编码是另一个编码的前缀。

本题中,需要解决的是一个非常类似的问题:按字典序从小到大,给出 $n$ 种不同字符及其频率,试为每个字符给出一个 $k$ 进制字符串(即,字符串中的每个字符为 $0\sim k-1$ 中的一个)作为编码,使得 $\text{频率}\times\text{码长}$ 之和最小,且没有任何一个编码是另一个编码的前缀。同时,你还需要保证给出的编码在字典序上是保序的,即,不会出现两个字符 $a,b$,使得字典序上 $a$ 比 $b$ 小,但是 $a$ 的编码比 $b$ 的编码的字典序大。

只需输出最小的 $\text{频率}\times\text{码长}$ 之和即可。

输入格式

第一行两个正整数 $n,k$,含义如题面中所述。

第二行 $n$ 个正整数 $a_1,a_2\ldots,a_n$,其中 $a_i$ 表示字典序第 $i$ 小的字符的频率。

输出格式

输出一个整数,表示答案。

样例输入1

6 2
1 4 5 4 1 5

样例输出1

50

样例输入2

15 3
5 6 8 10 7 3 6 6 9 5 9 6 6 1 4

样例输出2

227

样例3、4

见下发文件。

数据范围

对于所有数据,$2\le n\le 500;2\le k\le 60;a_i \le 10^9$。

测试点编号 $n\le$ $k\le$
$1\sim 3$ $10$ $5$
$4\sim 5$ $60$ $10$
$6\sim 8$ $500$ $10$
$9\sim 10$ $500$ $60$

发现在哈夫曼树的一棵子树所代表的那些数,对应出来一定是原序列的一个区间。所以考虑区间dp.

定义 \(dp_{l,r,k}\) 为现在递归到区间 \([l,r]\),有 \(k\) 个叶子节点可以填的情况。发现所谓有 \(k\) 个叶子可以填,其实就是把这个区间分成 \(k\) 份。定义 \(dp_{l,r,i}\) 表示把这个区间分成 \(i\) 份后的价值和,然后 \(dp_{l,r,1}=dp_{l,r,k}+s_r-s_{l-1}\)。最终答案为 \(dp_{1,n,1}\)。

发现对于每一个区间,我们只需要 \(dp_{l,r,1}\) 和 \(dp_{l,r,k}\) 的值。而 \(dp_{l,r,l}\) 可以用一个倍增之类的东西求出来。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=505;
int n,k,v[N],t[N],idx;
LL s[N],a[N],dp[N][N][16];
void dfs(int x)
{
	if(t[x])
		return;
	if(x==1)
		return;
	v[++idx]=x,t[x]=idx;
	dfs(x/2);
	dfs((x+1)/2);
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i),s[i]=s[i-1]+a[i];
	dfs(k);
//	for(int i=1;i<=n;i++)
//		dp[i][i][t[1]]=a[i];
	for(int len=2;len<=n;len++)
	{
		for(int i=1;i+len-1<=n;i++)
		{
			int j=i+len-1;
			memset(dp[i][j],0x3f,sizeof(dp[i][j]));
			for(int p=1;p<=idx;p++)
			{
				if(v[p]==1)
					continue;
				int lc=t[v[p]/2],rc=t[v[p]-v[p]/2];
				for(int l=i-1;l<=j;l++)
					dp[i][j][p]=min(dp[i][j][p],dp[i][l][lc]+dp[l+1][j][rc]);
//				printf("%d %d %d %d\n",i,j,v[p],dp[i][j][p]);
			}
			dp[i][j][t[1]]=dp[i][j][t[k]]+s[j]-s[i-1];
		}
	}
	printf("%lld",dp[1][n][t[1]]);
}

标签:编码,le,哈夫曼,10,text,样例,dp
From: https://www.cnblogs.com/mekoszc/p/16837673.html

相关文章

  • 7-1 哈夫曼编码
    给定一段文字,如果我们统计出字母出现的频率,是可以根据哈夫曼算法给出一套编码,使得用此编码压缩原文可以得到最短的编码总长。然而哈夫曼编码并不是唯一的。例如对字符串"aa......
  • 哈夫曼树及python实现
    3.1基本概念路径和路径长度:树中一个结点到另一个结点之间的分支构成这两个结点之间的路径;路径上的分枝数目称作路径长度,它等于路径上的结点数减1.结点的权和带权路径长度......
  • 哈夫曼树
    建立例如由权值分别为(1,2,3,4)四个节点,并分别设为树;循环得出()中权值最小的两个树,时期分别作为lchild与rchild,权值相加得到其根节点,作为新树,回归括号。再次调用以上函数,直至()中......
  • 哈夫曼编码解码(数据结构实验)
    哈夫曼树定义定义:带权路径长度WPL最小的二叉树称作哈夫曼树,又叫最优二叉树节点的带权路径长度为:从该节点到树根之间的路径长度与节点上的权的乘积树的带权路径长度为:......
  • 哈夫曼编码
    背景假如我们要传输一段文本,比如“hello”,怎么办?最容易想到的方法是,直接依次传输每个字符的Unicode,每个字符都用8个比特来传输。这样就需要5*8=40个比特来传输。但是如果......
  • 哈夫曼编码HuffmanCoding原理详解
    哈夫曼编码(\(Huffman\)\(Coding\))原理详解一、哈夫曼编码简介哈夫曼编码,又称为霍夫曼编码(\(Huffman\)\(Coding\))是一种可变长编码(\(VLC\),\(variable\)\(length\)......
  • 哈夫曼编码
    哈夫曼编码(Huffmancode)引言:哈夫曼编码是一种压缩编码的编码算法,是基于哈夫曼树的一种编码方式。(哈夫曼树详见:哈夫曼树)哈夫曼编码跟ASCII编码有什么区别?ASCII编......
  • 哈夫曼树
    哈夫曼树一、定义:给定N个权值作为N个叶子结点,构建一颗二叉树,使该树的WPL(带权路径长度)最小,即为一颗哈夫曼树(又称最优二叉树)。二、相关知识:路径和路径长度(L):树中的每一......
  • C++ 漫谈哈夫曼树
    1.前言什么是哈夫曼树?把权值不同的n个结点构造成一棵二叉树,如果此树满足以下几个条件:此n个结点为二叉树的叶结点。权值较大的结点离根结点较近,权值较小的结点离根......
  • 二叉树/前中后序遍历/二叉搜索树/哈夫曼树
    参考资料遍历的非递归写法目录中序遍历前序遍历后序遍历二叉搜索树插入节点删除节点哈夫曼树练习题中序遍历左子树-->根节点-->右子树,在访问完成根节点后,接下来访问的......