问题:
设有n 堆石子,要将其有次序的合并为一堆,规定在合并过程中每次至少选2堆最多选k 堆石子合并成新的一堆,2≤k≤n,合并的费用为新的一堆的石子数。计算出将n 堆石子合并成一堆的最大及最小费用。
样例输入:
首先输两个整数,表示n,k,而后输入n个数,表示n堆石子的个数
7 3
45 13 12 16 9 5 22
样例输出:
593 199
思路:
首先对于最大费用,很容易理解为Huffman树的倒序,即每次选的两个结点为值最大的,是得其权值最大
对于最小费用,即为多元Huffman,当余下的元素个数大于k,每次选前k小个,类似Huffman一样建树即可,然后求得最小带权路径和。
以样例为例:
在小顶堆优先队列的存储顺序为: 5 9 12 13 16 22 45 ,每次最多可以一次性合并3个,
首先 ,当队列长度大于等于3时,取前三个合并,释放掉,所得的和重新插入队列中,并记录此次合并所用的费用。
当队列长度小于3时,把剩余的元素全部合并即可,并记录费用(即石子的总个数);
下面是求最小费用的代码,借助优先队列实现:
#include <bits/stdc++.h> using namespace std; int main() { int n,k;//n表示初始多少堆石子,k表示一次最多合并多少堆 scanf("%d%d",&n,&k); priority_queue <int, vector<int>, greater<int> > que; int num; for(int i=0;i<n;++i) { scanf("%d",&num); que.push(num); } int sum1=0,sum=0;//记录费用 int x,y,z; while(que.size()>1) { if(que.size()>=k) { for(int i=1;i<=k;++i)//每次取前k小个 { int a=que.top(); que.pop(); sum+=a; sum1+=a; } que.push(sum1); sum1=0; } else { int er=que.size(); for(int i=1;i<=er;++i)//剩余的个数小于k个,全部拿出 { int a=que.top(); que.pop(); sum+=a; } // que.push(sum); } } cout <<sum<< endl; return 0; }