【NOI题解】 3.7数据结构之堆

来源:互联网 发布:淘宝卖家优惠券链接 编辑:程序博客网 时间:2024/06/10 03:18

NOI题目地址( 3.7数据结构之堆 ):http://noi.openjudge.cn/ch0307/

这里写图片描述

【NOI 2726:集合问题】

分析:

将K个数放到N个集合中,使得偏差值之和最小。

算法

n个数可能有1~n个集合,假设最优解有k个集合,那么构造一个k个节点的小根堆,小根堆的每个节点代表对应集合中的负荷值,每次取一个数据累加到堆顶,当所有的数据分配完成,由小根堆节点数据计算出的偏差值之和一定是所有可能中最小的。由此:
1. 最优解的集合个数是k(1~n范围内的某个数),尝试每种可能,构造小根堆
2. 构造一个k个节点的小根堆,小根堆的每个节点代表对应集合中的负荷值,小根堆节点个数为k,节点初始值为0
3. 依次将序列中的数据,累加到堆顶
4. 计算偏差值之和,维护一个偏差值之和的最小值,将计算结果与最小值进行比较
5. 偏差值最小的可能对应的集合个数为我们想要求解的结果

举例

对于数据4 3 3,可能有1、2、3个集合
1个集合对应:10
2个集合对应:4 6
3个集合对应:3 3 4
计算偏差比之和,发现集合数为3时,值最小且集合数目最大。
这里写图片描述

具体实现

借助了STL的priority_queue来实现堆
【STL】 priority_queue

AC题解:
#include <queue>#include <vector>#include <iostream>#include <algorithm>using namespace std;int main(){    //优先队列底层使用vector作为容器    priority_queue<int,vector<int>,greater<int>> heap;//小根堆    //数据    vector<int> nums;    int count;    cin>>count;    for(int i=0;i<count;i++)    {        int num;        cin>>num;        nums.push_back(num);    }    sort(nums.begin(),nums.end(),greater<int>());    int max = nums[0]; //找出最大值作为标准    //假设有1-n个集合,尝试每种可能,取最小偏差和最小的集合个数    int result = 0;    int min_Value = 0x7fffffff; //INT_MAX    for(int k=1;k<=count;k++)    {        heap.push(nums[0]); //最大值入堆        //构造一个k个节点的小根堆的小根堆        int value = 0;        for(int i=1;i<k;i++)        {            heap.push(0);        }        // 分配数据        for(int i=1;i<count;i++)        {            int min = heap.top();            heap.pop();            heap.push(min+nums[i]);        }        // 计算偏差和        while(!heap.empty())        {            // cout<<heap.top()<<" ";            value+=abs(heap.top()-max);            heap.pop();        }        // cout<<endl;        // 寻找偏差和最小的可能        if(value<=min_Value)        {            // cout<<value<<" "<<min_Value<<endl;            min_Value = value;            result = k;        }       }    cout<<result;    return 0;}
原创粉丝点击