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 }