Stall Reservations(POJ)奶牛挤奶

有 n头牛(1<=n<=50,000)要挤奶。给定每头牛挤奶的时间区
间[A,B] (1<=A<=B<=1,000,000,A,B为整数)。
牛需要呆畜栏里才能挤奶。一个畜栏同一时间只能容纳一头牛。
问至少需要多少个畜栏,才能完成全部挤奶工作,以及每头牛都
放哪个畜栏里(Special judged)
去同一个畜栏的两头牛,它们挤奶时间区间哪怕只在端点重合也
是不可以的

方法:贪心算法

所有奶牛都必须挤奶。到了一个奶牛的挤奶开始时间,就必须为这个奶
牛找畜栏。因此按照奶牛的开始时间逐个处理它们,是必然的
S(x)表示奶牛x的开始时间。E(x)表示x的结束时间。对E(x), x可以是奶牛
,也可以是畜栏。畜栏的结束时间,就是正在其里面挤奶的奶牛的结束
时间。同一个畜栏的结束时间是不断在变的。

1) 把所有奶牛按开始时间从小到大排序。
2) 为第一头奶牛分配一个畜栏。
3) 依次处理后面每头奶牛i。处理 i 时,考虑已分配畜栏中,结束时间最
早的畜栏x。
若 E(x) < S(i), 则不用分配新畜栏,i可进入x,并修改E(x)为E(i)
若 E(x) >= S(i),则分配新畜栏y,记 E(y) = E(i)
直到所有奶牛处理结束
需要用优先队列存放已经分配的畜栏,并使得结束时间最早的畜栏始终
位于队列头部。

证明:
由于按开始时间的顺序处理奶牛是必然,且按该算法,为奶牛i分配新
畜栏时,确实是不得不分配的,所以算法正确。
复杂度: O(nlogn)

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
struct Cow {
	int a,b;//挤奶区间的起始位置 
	int No; //编号 
	bool operator<(const Cow &c) const
	{ return a<c.a;             //<用sort排序是从小到大排序的 
	}
}cows[50100];
int pos[50100];//pos[i]表示编号为i的奶牛的畜栏编号
//优先队列
struct Stall{
	int end;
	int No;
	bool operator<(const Stall &s) const{
	 return end> s.end;  }//优先队列  此时的>代表最小值在前面,最小的优先级越高 
	 Stall(int e,int n):end(e),No(n){ }
}; 
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&cows[i].a,&cows[i].b);
		cows[i].No=i;
	}
	sort(cows,cows+n);
	int total=0;
	priority_queue<Stall> pq;//priority_queue 优先队列,其底层是用堆来实现的。在优先队列中,队首元素一定是当前队列中优先级最高的那一个。
	for(int i=0;i<n;i++)
	{
		if(pq.empty())//如果队列为空,则返回真值
		{
			++total;
			pq.push(Stall(cows[i].b,total));//加入第一个奶牛的结束时间 
			pos[cows[i].No] = total;//更新编号为 cows[i].No的畜栏的编号 
		}
		 else
		 {
		 	Stall st = pq.top();//返回优先队列对顶元素 
		 	if(st.end<cows[i].a){//端点不能重合,即 不能有= 
		 		pq.pop();//删除对顶元素
				pos[cows[i].No] = st.No;
				pq.push(Stall(cows[i].b,st.No)) ; 
				  
			 } 
			 else{ //对应 if(std.end < cows[i].a) 
			 	++total;
				 pq.push(Stall(cows[i].b,total)) ;
				 pos[cows[i].No] = total;
			 }
		  } 
	 }
	 printf("%d\n",total);
	 for(int i=0;i<n;i++)
	 {
	 	printf("%d\n",pos[i]); 
	  } 
	  return 0;
}

二、priority_queue

基本操作:

empty()      如果队列为空,则返回真

pop()    删除对顶元素,删除第一个元素

push()        加入一个元素

size()      返回优先队列中拥有的元素个数

top()     返回优先队列对顶元素,返回优先队列中有最高优先级的元素

在默认的优先队列中,优先级高的先出队。在默认的int型中先出队的为较大的数。

头文件:

#include <queue>

声明方式:

1、普通方法:

priority_queue<int> q;                 //通过操作,按照元素从大到小的顺序出队

priority_queue<int,vector<int>, greater<int> > q;    //通过操作,按照元素从小到大的顺序出队

2、自定义优先级:

struct cmp {     

  operator bool ()(int x, int y)     

  {        

     return x > y;   // x小的优先级高       //也可以写成其他方式,如: return p[x] > p[y];表示p[i]小的优先级高

  }

};

priority_queue<int, vector<int>, cmp> q;    //定义方法

//其中,第二个参数为容器类型。第三个参数为比较函数。

3、结构体声明方式:

struct node {     

  int x, y;     

  friend bool operator < (node a, node b)     

  {         

    return a.x > b.x;    //结构体中,x小的优先级高     

  }

};

priority_queue<node>q;   //定义方法

//在该结构中,y为值, x为优先级。

//通过自定义operator<操作符来比较元素中的优先级。

//在重载”<”时,最好不要重载”>”,可能会发生编译错误

猜你喜欢

转载自blog.csdn.net/adiamond1/article/details/81508346