zoukankan      html  css  js  c++  java
  • [扫描线]POJ2932 Coneology

    题意:有n个圆 依次给了半径和圆心坐标  保证输入的圆不相交(只有 相离 和 内含/外含 的情况)
         问 有几个圆 不内含在其他圆中,并分别列出这几个圆的编号(1~n)

        (n的范围是[1, 40000])

    案例画出来大概是这样的

    (那个原点为(50,50)的太远了,就意思一下)

    所以答案是3号圆和5号圆 不被包含

    好了,若这道题n只有1000,那么只要for两层,每个圆与另外的圆比较, 判断圆心是否在其他圆内即可判断是否包含

    这样的复杂度是O($n^2$)

    可是现在n有40000,显然不能用O($n^2$)来解决

    由这道题,简单粗暴的学习了一下扫描线, 复杂度为O(nlogn)

    什么是扫描线呢?

    顾名思义,就是一根线,扫描过去。

    怎样的一根线,怎么扫过去呢?

    ①平行于x轴,自上而下/自下而上 扫描

    ②平行于y轴,自左而右/自右而左 扫描

    ③绕圆心 逆时针/顺时针 扫描

    扫描线要干什么呢?

    “扫描线在平面上按给定轨迹移动的同时,不断根据扫描线扫过部分更新信息,从而得到整体所要求的结果”

    这道题,可以用上述的①/②

     自左而右扫描时,只有当扫描线移动到圆的左右两端时,线与圆的关系才会发生改变,因此先把圆的左右端点取出来排个序

    每当遇到某圆的左端点,判断该圆是否包含在其他圆内

    因为所有的圆都不相交,因此,每个圆都只可能包含在上下两个与它最相近的圆中

    (此处“上下两个”是通过比较 圆心的纵坐标 来确定的)

    也就是 每当我们得到一个不包含在其他圆中的圆,我们需要将它存起来,并将这些圆按圆心的纵坐标排序 以便与下一个扫到的圆进行比较

    我们可以用set<pair<double, int> >来存 (pair.first是圆心的纵坐标,pair.second是圆的编号) set会自动按pair.first排序

    当我们扫到某圆的右端点时,表示该圆的影响范围已经扫完了,后面扫到的圆不可能包含在该圆中,因此可以把该圆从set中去掉

    查找“上下两个与它最近的圆”的复杂度为O(logn) 

    因此遍历n个圆的复杂度为O(nlogn)

     1 const int N=40005;
     2 
     3 double x[N], y[N] ,r[N];
     4 
     5 bool inside(int i, int j) // i是否在j内
     6 {
     7     double dx=x[i]-x[j], dy=y[i]-y[j];
     8     return dx*dx+dy*dy<=r[j]*r[j];
     9 }
    10 
    11 int main()
    12 {
    13     int n;
    14     while(~scanf("%d", &n))
    15     {
    16         for(int i=0;i<n;i++)
    17             scanf("%lf%lf%lf", &r[i], &x[i], &y[i]);
    18         vector<pair<double, int> > X;
    19         for(int i=0;i<n;i++)
    20         {
    21             X.push_back(make_pair(x[i]-r[i], i));  //
    22             X.push_back(make_pair(x[i]+r[i], i+n));//
    23         }
    24         sort(X.begin(), X.end());
    25         set<pair<double, int> > out;
    26         vector<int> ans;
    27         for(int i=0;i<X.size();i++)  // 从左到右扫描
    28         {
    29             int id=X[i].second%n;
    30             if(X[i].second<n)  //
    31             {
    32                 set<pair<double, int> >::iterator it=out.lower_bound(make_pair(y[id], id));
    33                 if(it!=out.end() && inside(id, it->second)) // id 在 前一个圆内 不加入
    34                     continue;
    35                 if(it!=out.begin() && inside(id, (--it)->second)) // id 在 后一个圆内 不加入
    36                     continue;
    37                 ans.push_back(id);
    38                 out.insert(make_pair(y[id], id));
    39             }
    40             else  //
    41                 out.erase(make_pair(y[id], id));
    42         }
    43         sort(ans.begin(), ans.end());
    44         printf("%d
    ", ans.size());
    45         for(int i=0;i<ans.size();i++)
    46             printf("%d%c", ans[i]+1, i+1==ans.size()? '
    ':' ');
    47     }
    48     return 0;
    49 }
    POJ 2932
  • 相关阅读:
    poj 2418 Hardwood Species
    hdu 3791 二叉搜索树
    九度oj 1544 数字序列区间最小值
    九度oj 1525 子串逆序打印
    九度oj 1530 最长不重复子串
    九度oj 1523 从上往下打印二叉树
    P1190 接水问题
    P1179 数字统计
    P1083 借教室
    P1079 Vigenère 密码
  • 原文地址:https://www.cnblogs.com/Empress/p/4643074.html
Copyright © 2011-2022 走看看