H - Tokens on the Segments(ZOJ 4120)

Time Limit : 1 Second      Memory Limit : 65536 KB

Source : 第十届山东省ACM省赛

Problem Link : ZOJ 4120

Author : hiang  Date : 2019-5-19

 

题目大意:

  在二维坐标系中给出n条线段,第i条线段的两个端点分别为(li,i)和(ri,i),每个整数点都可以被标记,但是被标记的点x坐标不能相同,求至少有一个点被标记的线段最多有多少条

基本思路:贪心+优先队列

1.要使标记的线段最多,一条线段上只需标记一个点

2.尽可能标记短的线段,使更多线段可以被标记

3. 先对所有线段按左端点从小到大,左端点相同时按右端点从小到大的顺序进行排序

4.可选线段中左端点最小,且在与它左端点相同的所有线段中右端点最小的线段,标记左端点,对于与它左端点相同的其他线段则只能标记该点之后的点->优先队列

5.队首线段左端点可标记则出队,计数器加一,若队首线段左端点已被标记,则将该线段左端点加一后再入队(保证左端点小于等于右端点)

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 using namespace std;
 5 struct Segment
 6 {
 7     int l,r;//左右端点x坐标
 8     bool operator<(Segment a) const
 9     {
10         if(l==a.l)
11             return r>a.r;
12         return l>a.l;
13     }
14 };
15 priority_queue<Segment> q;
16 int main()
17 {
18     int T,n,ans,x,y;
19     scanf("%d",&T);
20     while(T--)
21     {
22         ans=0;
23         while(!q.empty())//清空队列
24             q.pop();
25         scanf("%d",&n);
26         while(n--)
27         {
28             Segment t;
29             scanf("%d%d",&x,&y);
30             t.l=x;
31             t.r=y;
32             q.push(t);//将所有线段加入队列
33         }
34         int k=0;//k记录上一个被标记的点的x坐标
35         while(!q.empty())
36         {
37             Segment u=q.top();
38             q.pop();
39             if(u.l==k)//若左端点已被标记,则左端点x坐标加一
40             {
41                 u.l++;
42                 if(u.l<=u.r)//得到的新线段符合要求则入队
43                     q.push(u);
44             }
45             else//若左端点没被标记,则k记为左端点,计数器加一
46             {
47                 k=u.l;  ans++;
48              }
49         }
50         printf("%d\n",ans);
51     }
52     return 0;
53 }

 

posted @ 2019-05-19 20:39  CSGO_BEST_GAME_EVER  阅读(693)  评论(0编辑  收藏  举报