【HDU5884】K叉哈夫曼树

本文介绍了一种使用双队列模拟构建K叉哈夫曼树的方法,以解决合并多个数值的最小代价问题。通过排序和二分查找,实现了O(n)的高效建树过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.题目链接。题目大意,合并k个数需要付出的代价是这k个数之和,求最小的k使得把n个数合并成一个数的代价最小。

2.看到这个先是模拟了一下,然后就发现了之前似乎做过这种操作。。。。。没错,就是在写压缩的时候写的哈夫曼树。(不懂哈夫曼树的童鞋自己补一下哈)。行了,那这个就是k叉哈夫曼树了。如何构造k叉哈夫曼树呢?我们在二叉哈夫曼树是采用堆来辅助建树,当然是可以的。我们也可以有更加高效的方法,就是采用双队列模拟。这样把数组排个序,剩下的就是O(n)的建树了。然后二分答案即可。还是挺有趣的一个题目的。


#include<bits/stdc++.h>
#include<queue>
#define ll long long
const int N = 1e5 + 5;
int n, m;
int a[N];
using namespace std;
queue<ll>q1, q2;
#pragma warning(disable:4996)
//构建K叉的哈夫曼树
int check(int k)
{
	while (!q1.empty())
		q1.pop();
	while (!q2.empty())
		q2.empty();
	int num = (n - 1) % (k - 1);
	ll t, s = 0;
	if (num)
	{
		for (int i = 0; i < k - 1 - num; i++)
		{
			q1.push(0);//这个时候,节点是不够的,需要新加节点进入
		}
	}
	for (int i = 1; i <= n; i++)
		q1.push(a[i]);
	while (true)
	{
		t = 0;
		int x1, x2;
		for (int i = 1; i <= k; i++)
		{
			if (q1.empty() && q2.empty())
				break;
			if (q1.empty())
			{
				t += q2.front();
				q2.pop();
				continue;
			}
			if (q2.empty())
			{
				t += q1.front();
				q1.pop();
				continue;
			}
			x1 = q1.front();
			x2 = q2.front();
			if (x1 < x2)
			{
				t += x1;
				q1.pop();
			}
			else
			{
				t += x2;
				q2.pop();
			}
		}
		s += t;
		if (q1.empty() && q2.empty())
			break;
		q2.push(t);
	}
	if (s <= m)
		return 1;
	else
		return 0;
}
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &a[i]);
		}
		sort(a + 1, a + n + 1);
		int l = 2, r = n;
		while (l < r)
		{
			int mid = (l+r)/ 2;
			if (check(mid))
				r = mid;
			else
				l= mid+1;
		}
		printf("%d\n", r);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值