zoj 4120 "Tokens on the Segments" (贪心+优先级队列 or 贪心+暴力)

传送门

题意:

  

题解:

  方法①:贪心+优先级队列

  贪心策略:按 L 从小到大排,L相同按 R 从小到大排;

  将着 n 条线段加入到优先级队列中,优先级队列的排序规则如上;

  定义 curX : 假象的一根线,从 0 位置扫描到 max{R} 位置;

  通过优先级队列找出 curX 位置需要放置硬币的最优线段;

  如何通过优先级队列实现呢?

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e5+50;
 4 
 5 int n;
 6 struct Date
 7 {
 8     int l,r;
 9     bool operator < (const Date &obj) const
10     {
11         if(l != obj.l)
12             return l > obj.l;
13         return r > obj.r;
14     }
15 }_date[maxn];
16 
17 int Solve()
18 {
19 //    Compress();
20     priority_queue<Date >q;
21     while(!q.empty())
22         q.pop();
23     for(int i=1;i <= n;++i)
24         q.push(_date[i]);
25 
26     int ans=0;
27     int curX=0;
28     while(!q.empty())
29     {
30         Date tmp=q.top();
31         q.pop();
32         /**
33             如果 l <= curX,那么[l,curX]是已求出最优解的的位置
34             对于当前的[l,r]线段,只需要的其[curX+1,r]片段
35             因为[curX+1,r]可能会对答案有贡献,所以将其加入到q中
36         */
37         if(tmp.l <= curX && curX+1 <= tmp.r)
38             q.push(Date{curX+1,tmp.r});
39         else if(tmp.l > curX)///如果l > curX,更新ans,curX
40         {
41             curX=tmp.l;
42             ans++;
43         }
44     }
45     return ans;
46 }
47 int main()
48 {
49 //    freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
50     int test;
51     scanf("%d",&test);
52     while(test--)
53     {
54         scanf("%d",&n);
55         for(int i=1;i <= n;++i)
56             scanf("%d%d",&_date[i].l,&_date[i].r);
57 
58         printf("%d\n",Solve());
59     }
60     return 0;
61 }
View Code

  方法②:贪心+暴力

  贪心策略:按 R 从小到大排,R 相同按 L 从小到大排;

  从 1~n 遍历每个线段,对于第 i 条线段,暴力查找 [L,R] 最左的空位置;

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ls(x) (x<<1)
 5 #define rs(x) (x<<1|1)
 6 const int maxn=1e5+50;
 7 
 8 int n;
 9 set<int >_set;
10 struct Date
11 {
12     int l,r;
13     int len;
14     bool operator < (const Date &obj) const
15     {
16         return r < obj.r;
17     }
18 }_date[maxn];
19 
20 int Solve()
21 {
22     sort(_date+1,_date+n+1);
23     _set.clear();
24 
25     int ans=0;
26     for(int i=1;i <= n;++i)
27     {
28         int l=_date[i].l;
29         int r=_date[i].r;
30         for(int j=l;j <= r;++j)
31         {
32             if(_set.find(j) == _set.end())///查找第i条线段可以放置硬币的最左的位置
33             {
34                 _set.insert(j);
35                 ans++;
36                 break;
37             }
38         }
39     }
40     return ans;
41 }
42 int main()
43 {
44     int test;
45     scanf("%d",&test);
46     while(test--)
47     {
48         scanf("%d",&n);
49         for(int i=1;i <= n;++i)
50         {
51             scanf("%d%d",&_date[i].l,&_date[i].r);
52             _date[i].len=_date[i].r-_date[i].l+1;
53         }
54         printf("%d\n",Solve());
55     }
56     return 0;
57 }
View Code

因为,如果输入 1e5 个线段,所有线段的左右端点全部为 [1,1e9];

那么,这个算法的时间复杂度为 O(n2logn);

这个时间复杂度在打比赛的时候是不敢想的啊;

虽然不能说是正解,但可以借鉴一下其贪心的思路(tql);

疑惑:这道题在离散化后跑一边方法①的代码wa了???

感觉,离散化后不影响结果啊??

猜你喜欢

转载自www.cnblogs.com/violet-acmer/p/10872557.html