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了???

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

转载于:https://www.cnblogs.com/violet-acmer/p/10872557.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个使用优先队列(priority queue)的题目,可以使用C++ STL中的优先队列来实现。 以下是样例代码: ```c++ #include <iostream> #include <queue> // 包含 priority_queue 头文件 using namespace std; int main() { int n; while (cin >> n) { priority_queue<int, vector<int>, greater<int>> pq; // 定义小根堆 for (int i = 0; i < n; i++) { int x; cin >> x; pq.push(x); // 将元素加入优先队列 } int ans = 0; while (pq.size() > 1) { // 只要队列中还有两个及以上元素 int a = pq.top(); pq.pop(); int b = pq.top(); pq.pop(); ans += a + b; pq.push(a + b); // 新元素入队 } cout << ans << endl; } return 0; } ``` 在这个代码中,我们使用了C++ STL中的优先队列 `priority_queue`,它有三个模板参数: - `int`:表示队列中存储的元素类型是 `int`。 - `vector<int>`:表示队列内部使用 `vector` 作为基础容器。 - `greater<int>`:表示使用小根堆来存储元素。 在主函数中,我们首先读入元素,然后将它们加入到优先队列中。接着,我们依次取出队列中的两个最小元素,将它们相加并累加到答案中,然后将它们的和作为新元素加入到队列中。最后,当队列中只剩下一个元素时,输出答案。 需要注意的是,在使用小根堆时,我们要将模板参数 `greater<int>` 作为第三个参数传递给 `priority_queue`。如果不指定第三个参数,则默认使用大根堆。 另外,这里使用了 `while (cin >> n)` 的方式来不断读入测试用例,直到遇到输入结束符为止(比如EOF或者Ctrl+Z)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值