【多元哈夫曼问题】

多元哈夫曼问题

问题描述

在一个操场的四周摆满了n堆石子。现要将石子有次序的合并成一堆,规定每次至少选2堆,最多选K堆石子合并成新的的一堆,合并的费用为新的一堆的柿子树。试设计一个算法,计算出将n对石子合并成最大费用和最小费用。
对于给定的n堆石子,计算合并成一堆的最大总费用和最小总费用

思路解析

  1. 求最大费用时只需将石堆排列后从大到小,两两进行合并即可。
  2. 求最小费用时,将石堆排列后,要尽可能的合并最少的次数且每次合并的石堆数为K堆在
  3. 求最小费用时,有时会出现特例,即每次合并K堆,最后一次合并时无法以K堆进行合并,
  4. 这样的话合并的结果就不是最小费用了,我们要将最小的堆合并最多次这样结果才会最小,
  5. 所以就要先判断原总堆数是否能使每次合并的堆数都为K堆,如果不能的话就要在原堆数前面加上 X 个个数为0的堆来补齐缺少的堆数

(1)分别创建一个递增的优先队列和一个递减的优先队列。创建队列的优点是可以对数字自动排序、取数等一些操作方便,如q.top();表示取队首元素。
(2)对于递增队列:① 先判断是否需要加“0”堆,需要就加;② 只要队列中的元素个数大于1(等价于队列中还至少有k堆石子,当然剩余石子堆数为k的整数倍),就对队列前k个元素进行处理。每次将队首加入到sum中,加完后就把队首弹出队列,继续处理下一个队首,直至处理了k个队首(即合并了k堆石子)。得到n个sum后,将sum累加起来,得到的就是最小费用。
(3)对于递减队列:方法同二,只是这里是连续处理2个

代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,k,x;
	long long maxsum=0,minsum=0;
	priority_queue<int,vector<int>,greater<int> >q1;//递增优先队列 
	priority_queue<int,vector<int>,less<int> >q2;
	cin>>n>>k;
	int i;
	for(int i=0;i<n;i++)
	{
		cin>>x;
		q1.push(x);
		q2.push(x);
	}
	
	int m=(k-((n+n/k)%k));
	for(int i=0;i<m;i++){
		q1.push(0); 
	}

	m+=n;
	while(q1.size()>1)
	{
		long long sum=0;
		for(int i=0;i<m;i++){
			sum+=q1.top();
			q1.pop();
		}
		minsum+=sum;
		q1.push(sum);
	}
	
	while(q2.size()>1){
		long long sum=0;
		for(int i=0;i<2;i++){
			sum+=q2.top();
			q2.pop();
		}
		
//		cout<<sum<<endl;
		maxsum+=sum;
		q2.push(sum);
	}
	
	cout<<"最大费用"<<maxsum<<endl;
	cout<<"最小费用"<<minsum<<endl; 
	return 0;	
} 

(⊙o⊙)…还有很多要写的,最近很忙考试周, 更新比较慢。。。先占个坑。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值