题目链接:https://cn.vjudge.net/problem/UVA-11776
题意:
给出数字n(0<=n<=1000),代表有n个农民,接下来有n行,每行两个数字S和E代表这个农民工作时间为[S,E];
每个农民工作时,需要有一个enforcer来监督,且每个enforcer一次只能监督一个农民;
求最少需要多少个enforcer.
题解:
这道题我也不太清楚算贪心还是算模拟,可能两者都有一点吧。
首先我们根据正常思维,既然要模拟分配监工去监督农民,那么肯定先给第一个开始做的农民分配一个监工;
所以我们自然而然的想到对农民按工作时间的起点S从小到大排序;
然后,我们也就会进一步自然的想到,如果下一个农民的工作时间和当前农民的工作时间有重合,就要再来一个监工;
但是,经过更加仔细的思考,
由于我们是按农民工作时间的起点S从小到大排,而非按工作终点E排,故可能出现问题:
3
1 5
2 3
4 10
这种情况,如果单纯地像上面说的那样算,就会算出需要3个监工,而事实上,只需要2个监工就够了。
所以,我们建立一个优先队列,用以存储表示每个监工的监督时间;
并且每个监工有两个变量l和r,表示在当前,监工的工作时间为[l,r],而优先队列按监督时间的终点从小到大维护。
这样一来,我们就有更加成熟的思路:
①把第一个的农民的工作时间[S,E]当做第一个监工的监督时间[l,r]存入优先队列。
②枚举之后的农民;
③获得队头的值(代表了当前所有监工中,最早空下来的那个),与当前农民进行比较:
若当前监工还未空闲,说明所有监工都没空,只能在加一个监工;
若当前监工已经空闲,可以监督当前农民,则取出队头,[l,r]修改成当前农民的[S,E]值,再push入优先队列;
④所有农民枚举完毕,ans = 优先队列的size;
AC代码:
1 #include<cstdio> 2 #include<queue> 3 #include<algorithm> 4 using namespace std; 5 struct Node{ 6 int l,r; 7 bool operator<(const Node &oth)const 8 { 9 return this->r > oth.r; 10 } 11 }node[1000+5]; 12 int n; 13 bool cmp(Node a,Node b){return a.l<b.l;} 14 int main() 15 { 16 int kase=0; 17 while(scanf("%d",&n) && n!=-1) 18 { 19 if(n==0) 20 { 21 printf("Case %d: 0 ",++kase); 22 continue; 23 } 24 25 priority_queue<Node> enforcer; 26 for(int i=0;i<n;i++) scanf("%d%d",&node[i].l,&node[i].r); 27 sort(node,node+n,cmp); 28 enforcer.push(node[0]); 29 for(int i=1;i<n;i++) 30 { 31 Node now=enforcer.top(); 32 if(node[i].l<=now.r) enforcer.push(node[i]); 33 else 34 { 35 enforcer.pop(); 36 now.l=node[i].l, now.r=node[i].r; 37 enforcer.push(now); 38 } 39 } 40 41 printf("Case %d: %d ",++kase,enforcer.size()); 42 } 43 }