mooc 贪心算法

分配畜栏

有n头牛(1<=n<=50000)要挤奶。给定每头牛挤奶的时间区间[A,B](1<=A<=B<=1000000,A,B为整数)。

牛需要呆畜栏里才能挤奶。一个畜栏同一时间只能容纳一头牛。

问至少需要多少个畜栏,才能完成全部挤奶工作,以及每头牛都放在哪个畜栏里

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

解题思路

先对所有奶牛开始时间排序
然后新开辟一个畜栏(再怎么样至少也有一个畜栏)
每一个畜栏就是一个优先队列,按照结束时间(会场安排、看电影的道理)从小到大排序
判断奶牛属于哪一个畜栏就是看这个奶牛的开始时间与前几个已经开辟完的畜栏的结束时间比,如果开始时间比结束时间段早,那就再分配新畜栏。
 

如果畜栏队列为空,我们就给它直接分配一个畜栏,将总共的畜栏序号++,然后把这头奶牛所放入的畜栏序号,就是当今的畜栏总号,填入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];   //pos[i]表示编号为i的奶牛的畜栏编号

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

大数据201  tyx

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值