不是hihocoder 1111 只是算哈弗曼编码长度

#1111 : Huffman编码

时间限制: 30000ms
单点时限: 3000ms
内存限制: 256MB

描述

给定一个大小为n的字符集Σ中每个字符出现的频数,求不同的Huffman编码的数量模109 + 7。

一个编码是一个从Σ到01字符串的函数。 一个Huffman编码是一个由以下过程生成的编码:

初始时每个字符为一个集合。初始时所有字符对应到空字符串。一个集合S的频数w(S)定义为S内所有字符的频数的和。 不断进行以下操作直到只剩下一个集合:

选择两个不同的集合A和B使得w(A) + w(B)最小。将A内所有字符对应到的字符串前端加上'0'。将B内所有字符对应到的字符串前端加上'1'。添加一个集合C,为A和B的并。删除A和B。

两个编码不同当且仅当存在一个字符对应到的01字符串不同。

输入

第一行,T,测试点个数。下面T个测试点。

对于每个测试点,第一行,n,为字符集Σ的大小。 第二行,n个整数w1, ..., wn. 其中wi为第i个字符的频数。

1 ≤ n ≤ 106. 所有n的和 ≤ 106. 1 ≤ wi ≤ 106.

输出

T行。每行为对应测试点的答案。

样例输入
5
1
1
2
1 1
3
1 1 1
4
1 1 1 1
4
1 1 2 2
样例输出
1
2
12
24
24
我得到的输出是:

1

2

5

8

12


代码如下:

#include<iostream>
using namespace std;
#include<functional>
#include<queue>
#include<vector>


struct node
{
	int x;
	vector<int> y;
	friend bool operator < (node a, node b){return a.x>b.x;}
};
int main()
{
	
	int cnt;
	cin>>cnt;
	while(cnt--)
	{
		priority_queue<node> que;

		int len;
		cin>>len;
		vector<int> chang(len,0);
		vector<int> quanzhong;
		for(int i=0;i<len;++i)
		{ int quan;
		node newnode;
		cin>>quan;
		quanzhong.push_back(quan);
		newnode.x=quan;
		newnode.y.push_back(i);
		que.push(newnode);
		}

		while(!que.empty())
		{
			if(que.size()==1)
			{
				//node a=que.top();
				que.pop();
				//int sz=a.y.size();
				//for(int i=0;i<sz;++i)
				//	chang[a.y[i]]++;
				if(len==1)
					chang[0]++;
			}else{
				node a=que.top();
				que.pop();
				node b=que.top();
				que.pop();
				int sz=a.y.size();
				for(int i=0;i<sz;++i)
					chang[a.y[i]]++;
				sz=b.y.size();
				for(int i=0;i<sz;++i)
					chang[b.y[i]]++;
				node c;
				c.x=a.x+b.x;
				c.y.insert(c.y.end(),a.y.begin(),a.y.end());
				c.y.insert(c.y.end(),b.y.begin(),b.y.end());
				que.push(c);
			}
		}
		int res=0;
		for(int i=0;i<len;++i)
			res+=chang[i]*quanzhong[i];
		cout<<res<<endl;
	}
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值