多元哈夫曼问题
问题描述
在一个操场的四周摆满了n堆石子。现要将石子有次序的合并成一堆,规定每次至少选2堆,最多选K堆石子合并成新的的一堆,合并的费用为新的一堆的柿子树。试设计一个算法,计算出将n对石子合并成最大费用和最小费用。
对于给定的n堆石子,计算合并成一堆的最大总费用和最小总费用
思路解析
- 求最大费用时只需将石堆排列后从大到小,两两进行合并即可。
- 求最小费用时,将石堆排列后,要尽可能的合并最少的次数且每次合并的石堆数为K堆在
- 求最小费用时,有时会出现特例,即每次合并K堆,最后一次合并时无法以K堆进行合并,
- 这样的话合并的结果就不是最小费用了,我们要将最小的堆合并最多次这样结果才会最小,
- 所以就要先判断原总堆数是否能使每次合并的堆数都为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⊙)…还有很多要写的,最近很忙考试周, 更新比较慢。。。先占个坑。