优先级队列:先来后到?不存在!(全面)

定义:

优先级队列相当于一个个容器,里面放着一些元素,也许有很多特征,假设有一个key值,优先级队列就是比较key值来排优先级的。其底层是靠堆来实现的。基本结构如下:

priority_queue <typename> name 

读者若不理解,我来举个例子:

假设有三种水果,名称,编号,价钱都不一样。我们希望价格越高的优先级越高。

        A    B    C  
node    3    2    1//编号 
price   4    5    6//价格
//那么在优先级队列中,C的优先级最高
//在这个例子中,price就是定义中的key值 

性质:

一.常用函数

1.top()

堆顶(队首),优先级最高  O(1)时间获得队首

跟queue的front是不一样的,别记错了

2.pop()

弹掉堆顶元素(队首元素)

3.empty()

检测队列是否为空,是空的返回true,否则返回false

4.push()

将x入队

5.size()

返回元素个数

二.设置

int型,double型,char型可以直接使用数据类型,优先级队列对他们的优先级设置一般是数字大的优先级高,char是字典序最大。

下面看个例子:

priority_queue<int> q;
priority_queue<int vector<int>,less<int> >q;
//这两种写法的优先级是一样的
//less<int> 表示数字大的优先级越大,而greater<int> 表示数字小的优先级越大
//其实这也很好理解,越来越小和越来越大嘛
//double和char同上
 

三.排序

还是以上文的水果为例

struct fruit
{
	string name;
	int price;
};

价格越高,优先级越高,排序有以下三种写法:

struct fruit
{
	string name;
	int price;
	
	bool operator < (const fruit &x) const
	{
	   return price<x.price;
	}
};
struct fruit
{
	string name;
	int price;
	
	friend bool operator < (fruit a,fruit b)//friend为友元
	{
		return a.price<b.price;
	}
	
};

这两种都是通过重载<的(其实从数学上来说,a>b等价于判断a<b)

注意,不要重载>,不然会出错的

如果你想改写成价格越低,优先级越大

那就把

a.price<b.price
//改成
a.price>b.price 

发现没?优先级队列的排序似乎跟sort中的cmp是反的呀?

其实也是可以换成cmp的写法,写在外面

struct cmp
{
	bool operator() (fruit a,fruit b)
	{
		return a.price<b.price;
	}
};

priority_queue<fruit,vector<fruit>,cmp> q;
//但要这样定义优先级队列,价格越高,优先级越高

友情提醒:struct的;不要丢掉,const和&可以提高效率

思想应用

看一到小例题:

某国正在进行大选,需要在城市中设置投票点来统计票数

现在有N(<=1000)个城市,共有M个投票点(<=5000)需要被放置到这些城市中,每个城市都至少有一个投票点。每个城市的选民被平均分配到这个城市的各个投票点。为了让统计票数时出错的概率最低,因此要使被分配到选民人数最多的投票点的选民人数越少越好,输出所有投票点中分配到最多选民的人数。

分析:

贪心策略

首先,先给每一个城市安排一个投票点,找出每个投票点分配到的选民人数最多的一个城市,然后多给这个城市一个投票点。以此类推,分配完剩下的所有投票点。具体实现时,采用优先级队列的思想,key值为该城市的每个投票点分配到的选民数。

当然看到最大值最小,二分答案一样可以解决。

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct node
{
	int num;//投票点个数 
	int p;//选民人数 
}a[50010];

int n,m,cnt;//cnt可以理解成城市 
int main() 
{
	cnt=1; 
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].p;
		a[cnt].num=1;
	}
	
	m-=n;//每个城市先一个投票点
	for(int i=1;i<=m;i++)
	{
		cnt=1;
		for(int j=2;j<=n;j++)
		{
			if((ll)a[cnt].p*(ll)a[j].num<(ll)a[cnt].num*(ll)a[j].p)
			//可以这样理解 :a[cnt].p/a[cnt].num<a[j].p/a[j].num 把人平均分配到投票点中
			//避免浮点数,采用乘法 
			 cnt=j; 
			 a[cnt].num++;//其实是j这个城市多了一个投票点 
		}
	 } 
	 
	 cnt=1;
	 for(int i=2;i<=n;i++)//找到最多的那一个 
	 {
	 	if((ll)a[cnt].p*(ll)a[i].num<(ll)a[cnt].num*(ll)a[i].p)
	 	 cnt=i;
	  }
	  
	int ans=a[cnt].p/a[cnt].num;
	if(a[cnt].p%a[cnt].num!=0) ans++;
	
	cout<<ans;
	return 0; 
}

 

PS:但这程序始终有问题

输入:

4 6

120

2680

3400

200

应该输出1700

但却输出1340

 

求救!!!! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值