石子堆积(多元Huffman)、贪心思想

问题:

    设有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;
}


猜你喜欢

转载自blog.csdn.net/qq_38297860/article/details/80485543
今日推荐