POJ3190 Stall Reservations - 优先队列

Stall Reservations

 
 

题目大概意思:

N N 头牛,第 i i 头牛的产奶时间为 [ A i , B i ] ( 1 A i B i 1 0 6 ) [A_i, B_i] (1≤A_i≤B_i≤10^6) , 一个房间在同一时间只能容纳一头牛产奶,问最少需要多少房间。输出最少需要的房间数,以及每头牛的产奶房间(编号从 1 1 开始)。

 
 

分析:

如果只问至少需要多少个房间,那么这个问题会简单很多,我们只需要统计每个时间点的正在产奶的牛的个数,然后输出最大值即可,可以用树状数组进行区间修改和单点询问来求出最大值,或运用差分序列,不过由于时间的取值范围高达 1 0 6 10^6 ,而时间限制只有 1 s 1s ,使用这种 O ( M log 2 M ) O(M\log_2{M}) 或 O(M) 的算法很可能超出时间限制,虽然可以运用坐标离散化删除无用的时间点,或直接运用区间修改的线段树实现 R M Q RMQ ,将时间复杂度降低至 O ( N ) O(N) O ( N log 2 N ) O(N\log_2{N}) ,但比较麻烦,且不易记录每头牛的房间信息。

因此我们使用优先队列:先按照每头牛的产奶开始时间 A A 进行非降序排序,从左到右依次遍历排好序的序列,用优先队列(priority_queue)存储在当前牛的产奶开始时间点 A A 正在产奶的牛,按产奶结束时间点从小到大作为优先队列的排序依据。这样一来,在从左往右遍历的时候,我们可以记录下每个需要考虑的时间点的正在产奶的奶牛,并以此作为分配房间的依据。具体做法是把每头牛表示为一个结构体,记录 A , B , n u m b , p o s A, B, numb, pos , 分别表示 产奶开始时间,产奶结束时间,牛的编号(输入顺序),牛的产奶房间号,用一个优先队列存储正在产奶的牛,一个队列(随便一个容器就可以)存储当前可用的房间的编号。在遍历过程中考虑当前牛之前,先令 B < B< (当前牛的 A A ) 的牛弹出优先队列,并将它使用的房间添加到可用房间的队列中。然后从可用房间的队列中取出一个房间号作为当前牛的产奶房间,即第 n u m b numb 头牛的产奶房间,最后把当前牛添加到优先队列中。

时间复杂度是 O ( N log 2 N ) O(N\log_2{N}) N N 只有 5 × 1 0 4 5×10^4 ,即使常数大一些也没有压力。

 
 
下面贴代码:

#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;


const int MAX_N = 50008;

// 表示牛的结构体
struct Cow
{
	int A;
	int B;
	int numb;
	int pos;
	bool operator< (const Cow& _Right)const
	{
		return A < _Right.A;
	}
	Cow() {}
};

// 用作堆的比较函数
struct greater_B
{
	bool operator() (const Cow& _Left, const Cow& _Right)const
	{
		return _Left.B > _Right.B;
	}
};

Cow cows[MAX_N];
int ans[MAX_N];

int main()
{
	int N;
	scanf("%d", &N);

	for (int i = 0; i < N; ++i)
	{
		Cow& cur = cows[i];
		scanf("%d%d", &cur.A, &cur.B);
		cur.numb = i;
	}
	sort(cows, cows + N);

	priority_queue<Cow, vector<Cow>, greater_B> pq;   // 存储正在产奶的牛的优先队列
	queue<int> q;                                     // 可用房间队列
	int stall = 0;                                    // 所需的最少房间数
	for (int i = 0; i < N; ++i)
	{
		Cow& cur = cows[i];
		while (!pq.empty() && pq.top().B < cur.A)
		{
			q.push(pq.top().pos);                     // 将已经产奶完成的牛使用的房间添加进可用房间的队列
			pq.pop();
		}

		if (q.empty()) q.push(++stall);               // 如果发现可用房间队列为空, 则令所需的最少房间数+1, 并将新的房间添加进去

		cur.pos = q.front();                          // 记录下当前牛使用的房间, 以便以后释放该房间
		q.pop();

		ans[cur.numb] = cur.pos;                      // 记录答案, 即令第 cur.numb 头牛使用的房间记为 cur.pos

		pq.push(cur);                                 // 将当前牛添加到正在产奶的牛的优先队列
	}

	printf("%d\n", stall);
	for (int i = 0; i < N; ++i)
	{
		printf("%d\n", ans[i]);
	}

	return 0;
}

原创文章 42 获赞 22 访问量 3056

猜你喜欢

转载自blog.csdn.net/weixin_44327262/article/details/97614375