ZOJ4120 贪心加优先队列

题目大意:

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

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

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

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

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

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

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

Sample Input

2
3
1 2
1 1
2 3
3
1 2
1 1
2 2

Sample Output

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

 

posted @ 2020-03-18 22:56  programmer_w  阅读(1)  评论(0)    收藏  举报