贪心---分配畜栏

题目描述:

有 n 头牛(1<=n<=50000)要挤奶。给定每头牛挤奶的时间区间 [A,B] (1<=A<=B<=1000000,A,B 为整数)。牛需要呆畜栏里才能挤奶。一个畜栏同一时间只能容纳一头牛。问至少需要多少个畜栏,才能完成全部挤奶工作,以及每头牛都放哪个畜栏里(Special judged)

去同一个畜栏的两头牛,它们挤奶时间区间哪怕只在端点重合也是不可以的

输入:

第 1 行:单个整数 N,表示一共多少头牛
第 2 行到 N + 1 行,每行两个整数,表示每头奶牛的挤奶时间间隔

输出:

一共需要多少个畜栏,每头奶牛应该放在哪个畜栏中

Sample Input

5
1 10
2 4
3 6
5 8
4 7

Sample Output

4
1
2
3
2
4

别人的思路:

我们来说说这题吧, 这是一道优先队列加上贪心的题目,主要是贪心。

我们首先按照奶牛的挤奶需求,把它们的挤奶时间按照挤奶的开始时间,从早到晚的顺序进行排列。然后我们就开始给它们分配畜栏。

我们认定每个奶牛都有一个序号,我们读入的时候,就给它从1到n-1写入它的序号里面。

分配的过程是这样的:

如果畜栏队列为空,我们就给它直接分配一个畜栏,将总共的畜栏序号++,然后把这头奶牛所放入的畜栏序号,就是当今的畜栏总号,填入pos数组,下标是奶牛的编号。

我们修改这个畜栏的结束时间,改成奶牛挤奶的结束时间,畜栏的序号也改成总的畜栏序号,之后压入优先队列。

如果畜栏队列不为空,就说明此时已经分配了畜栏,如果此时最早结束使用的畜栏,它的结束时间早于这头奶牛挤奶的开始时间,那我们就可以把这头奶牛放入这头畜栏。

我们把这个畜栏弹出优先队列,因为下一次压入之后的结束时间就改变了。

我们修改这个畜栏的结束时间为奶牛挤奶的结束时间,畜栏的序号不变。奶牛 i 的pos数组对应的位置修改成畜栏的序号,将畜栏压入优先队列。

如果最早结束的都不能满足的话,我们就重新给它分配一个畜栏,重复之前的队列为空的流程。

代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
 
struct Cow
{
	int start,end;
	int num;
	bool operator < (const Cow &b)const
	{
		return start<b.start;
	}
}cow[50050];
int pos[50050];
 
struct Stall
{
	int end;
	int num;
	bool operator < (const Stall &b)const
	{
		return end>b.end;
	}
	Stall(int a,int b):end(a),num(b){}
};
 
int main()
{
	int n;
	scanf("%d",&n);
	for (int i=0;i<n;i++)
	{
		scanf("%d%d",&cow[i].start,&cow[i].end);
		cow[i].num=i;
	}
	sort(cow,cow+n);
	int total=0; 
	priority_queue<Stall>pq;
	for (int i=0;i<n;i++)
	{
		if (pq.empty())
		{
			total++;
			pos[cow[i].num]=total;
			pq.push(Stall(cow[i].end,total));		
		}
		else {
			Stall st=pq.top();//结束时间最早的畜栏 
			if (st.end<cow[i].start)
			{
				pq.pop();
				pos[cow[i].num]=st.num;
				pq.push(Stall(cow[i].end,st.num));
			}
			else
			{
				total++;
				pos[cow[i].num]=total;
				pq.push(Stall(cow[i].end,total));
			}
		}
	}
	printf("%d\n",total);
	for (int i=0;i<n;i++)
	{
		printf("%d\n",pos[i]);
	}
	return 0;
}

我学到的:

大意就是:放牛进栏杆,到时间再放出来,有牛就放,若有其他牛到时间,出来时,就放进那头牛的栏杆中,否则新放个栏杆

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值