zoukankan      html  css  js  c++  java
  • The 10th Shandong Provincial Collegiate Programming Contest H.Tokens on the Segments(贪心+优先级队列 or 贪心+暴力)

    传送门

    •题意

      二维平面上有 n 条线段,每条线段坐标为 $(l_i,i),(r_i,i)$;

      平面上的每个整点坐标上都可以放置一枚硬币,但是要求任意两枚硬币的横坐标不相同;

      问最多有多少条线段可以放置硬币。

    •题解1

      考虑到当 $X=x$ 时,最多有一条线段可以放置一枚硬币;

      那么,我们可以从左到右查找最多有多少条线段可以放置硬币;

      定义变量 $X$ 表示 $[0,X]$ 位置已放置好硬币;

      既然是按照 $x$ 来的,那么我们就需要将所有可能可以放置硬币的线段按照 $l$ 升序排列,如果 $l$ 相同,按照 $r$ 升序排列;

      考虑用优先级队列,首先将所有线段放入优先级队列 $q$ 中,并定义 $X=0$;

      每次选择从 $q$ 的队头取出 $l$ 小的线段,判断这条线段的 $l'$ 与 $X$ 的位置关系:

        ①如果 $l' leq X$,说明当前这条线段的 $[l',X]$ 位置 不能放置硬币,只能考虑 $[X+1,r']$ 位置是否还可以放置硬币;

           那么,此时,我们就将 $[X+1,r_i]$ 丢到 $q$ 中,代表可能从 $[X+1,r']$ 中选择某位置放置硬币;

        ②如果 $l' > X$,说明 $[X,l')$ 间无可放置硬币的线段,那么我们要选择一枚硬币放置在 $l'$ 处,即当前这条线段上,并更新 $X=l'$;

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e5+50;
     4 
     5 int n;
     6 struct Heap
     7 {
     8     int l,r;
     9     bool operator < (const Heap &obj)const
    10     {
    11         if(l != obj.l)
    12             return l > obj.l;
    13         return r > obj.r;
    14     }
    15 };
    16 priority_queue<Heap >q;
    17 
    18 int Solve()
    19 {
    20     int X=0;
    21     int ans=0;
    22     while(!q.empty())
    23     {
    24         Heap tmp=q.top();
    25         q.pop();
    26 
    27         /**
    28             如果 tmp.l <= X,那么[tmp.l,X]是已求出最解的位置
    29             但是[X+1,tmp.r] 还是没有放置硬币的
    30             所以当前线段还是有可能在[X+1,tmp.rr]区间放置一枚硬币的
    31             所以将其加入到q中
    32         */ 
    33         if(tmp.l <= X && X+1 <= tmp.r)
    34             q.push({X+1,tmp.r});
    35         else if(tmp.l > X)///如果tmp.l > X,更新ans,X
    36         {
    37             ans++;
    38             X=tmp.l;
    39         }
    40     }
    41     return ans;
    42 }
    43 int main()
    44 {
    45     int T;
    46     scanf("%d",&T);
    47     while(T--)
    48     {
    49         while(!q.empty())
    50             q.pop();
    51 
    52         scanf("%d",&n);
    53         for(int i=1;i <= n;++i)
    54         {
    55             int l,r;
    56             scanf("%d%d",&l,&r);
    57             q.push({l,r});
    58         }
    59         printf("%d
    ",Solve());
    60     }
    61     return 0;
    62 }
    View Code

      

    •题解2

      贪心+暴力

      贪心策略:按 $r$ 从小到大排,$r$ 相同按 $l$ 从小到大排;

      从 1~n 遍历每个线段,对于第 i 条线段,暴力查找 $[l,r]$ 最左的为放置硬币的空位置;

    •Code

     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
    ",Solve());
    55     }
    56     return 0;
    57 }
    View Code

    •题解2分析

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

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

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

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

    •疑惑

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

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

  • 相关阅读:
    GC垃圾回收算法
    Docker+nginx部署Springboot+vue前后端分离项目
    报错 ImportError: cannot import name 'AsyncContextManager'
    Python+Selenium定位不到元素(报错:selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element)
    淘宝网的发展史及其优缺点
    Python旅途——函数(1)
    正则表达式 -允许输入数字和小数点后两位
    表单的resetFileds函数重置为初始值而非清空数据
    做一个全局登录弹窗,任何地方访问
    浏览器到服务器的跨域问题
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10872557.html
Copyright © 2011-2022 走看看