题目链接
题目大意:有N头奶牛需要分配牛棚挤奶,每一个牛挤奶都有一个区间,每个奶的区间不能重叠,端点一样都不行,问最少需要分配几个牛棚。
Hint
Explanation of the sample:
Here’s a graphical schedule for this output:
Time 1 2 3 4 5 6 7 8 9 10
Stall 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>>
Stall 2 … c2>>>>>> c4>>>>>>>>> … …
Stall 3 … … c3>>>>>>>>> … … … …
Stall 4 … … … c5>>>>>>>>> … … …
Other outputs using the same number of stalls are possible.
题目分析
思路一(超时思路,但是方法正确,是第二个思路的前身,值得一看)
- 利用贪心算法来做,需要设置一个visit来保存这头牛是否分配过
- 需要将牛按结束时间排序,结束越早越靠前
- 每次循环找到第一个未被访问过的奶牛,其终止时间作为t,然后再从这个奶牛开始向后寻找第一个start比这个奶头大的,然后再把这个奶牛结束时间为t,继续下去,知道所有奶牛分配完毕。
这个方法思路很简单,但就是时间复杂度太高,无法AC,其中重要一点就是如何寻找这个未被访问过的奶牛和寻找下一头奶牛花费时间太多,这里我们就想到了采用优先队列来解决这道题。
贴一下这个方法的代码
#include<iostream>
#include<cstdio>
#include<string>
#include<limits.h>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<set>
#include<vector>
#include<queue>
using namespace std;
struct P{
int start;
int end;
int num;
P(int x,int y):start(x),end(y){}
P(){}
bool operator <(const P& other){
if(end==other.end){
return start<other.start;
}
else{
return end<other.end;
}
}
}cow[50000];
bool cmp( P x, P y){
return x.num<y.num;
}
int pos[50000];
int main(){
int n;
bool visit[50000];
while(scanf("%d",&n)!=EOF){
memset(visit,false,sizeof(visit));
for(int i=0;i<n;i++){
scanf("%d%d",&cow[i].start,&cow[i].end);
cow[i].num=i+1;
}
int res=0;
int sum=0;
sort(cow,cow+n);
while(sum<n){
res++;
int t;
int j;
for( j=0;j<n;j++){
if(visit[j]==false){
t=cow[j].end;
sum++;
visit[j]=true;
pos[cow[j].num]=res;
break;
}
}
if(sum<n){
for(int i=j+1;i<n;i++){
if(visit[i]==false&&cow[i].start>t){
visit[i]=true;
t=cow[i].end;
sum++;
pos[cow[i].num]=res;
}
}
}
}
printf("%d\n",res);
for(int i=1;i<=n;i++){
printf("%d\n",pos[i]);
}
}
return 0;
}
思路二(AC)
- 题目虽然说是special Judge,但是好像牛棚顺序还是固定的,换言之,这道题答案还是固定的(但其实我们知道,牛棚顺序换一下情况是一样的)。正因为如此,所以我们不得不按开始时间先后对他们进行排序
- 接下来我们处理寻找奶牛的快速方法,这就要用到优先队列priority——queue,其中内部的排序方式是按结束时间早的在堆顶
- 然后我们就按数组顺序一个一个判断
①如果队列为空,那么我就需要加入当前队列,并记录该奶牛对应的牛棚序号
②如果队列不空
i 如果当前奶牛的开始时间比堆顶的奶牛要大,那么符合条件,入队,并且记录该牛的牛棚序号,并且将堆顶的奶牛pop,因为它后继有牛了
ii 如果当前奶牛的开始时间不大于堆顶的奶牛,那么直接入队,因为这头牛是剩下牛当中开始时间最早的了,但是和结束时间最早的奶牛相比,他都无法接上,那只能给他再分配一个牛棚,并记录牛棚号 - 如此往复,知道所有奶牛分配完毕,然后按奶牛的序号顺序逐一输出对应的牛棚号。
贴上代码
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
struct P{
int start;
int end;
int num;
P(int x,int y):start(x),end(y){}
P(){}
bool operator <(const P& other)const{
return start<other.start;
}
}cow[50000];
struct cmp{
bool operator ()(const P& x,const P& y)const{
return x.end > y.end;
}
};
int pos[50000];
int main(){
int n;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%d%d",&cow[i].start,&cow[i].end);
cow[i].num=i+1;
}
priority_queue<P,vector<P>,cmp> myQ;
sort(cow, cow + n);
int stall = 1;
for (int i = 0; i < n;i++){
if(myQ.empty()){
myQ.push(cow[i]);
pos[cow[i].num] = stall;
}
else if(cow[i].start>myQ.top().end){
P t = myQ.top();
myQ.push(cow[i]);
pos[cow[i].num] = pos[t.num];
myQ.pop();
}
else{
stall++;
myQ.push(cow[i]);
pos[cow[i].num] = stall;
}
}
printf("%d\n", stall);
for (int i = 1; i <= n;i++){
printf("%d\n", pos[i]);
}
}
return 0;
}