扫描线POJ2932

来源:互联网 发布:silverlight mac 卸载 编辑:程序博客网 时间:2024/05/22 00:42
思路转自 http://www.cppblog.com/Wangzhihao/articles/109348.html
考虑扫描线,选择一个圆的最左点和最右点作为事件点.然后用一条竖直线从左到右扫一遍.
    维护一个数据结构,里面保存着和扫描线相交的powerful 圆.
    如果一个事件是某圆的最右点,并且该圆在数据结构中,就意味着要把这个圆删掉.
    如果一个事件是某圆的最左点,当它不被其他圆包含时,就意味着可能要把它加入到我们的数据结构中,
怎么检查它有没有被其他圆包含呢?我们的数据结 构里的圆都是一些 powerful 圆,他们互不相交,也就是
说他们在当前的扫描线上占的区间也互不相交, 如果我们只是记录圆心在扫描线的投影, 把高的投影称为前,
把低的投影低称为后,那么可能与当前圆发生关系的只是它的前一个圆,后一个圆.


//平面上N个两两没有公共点的圆,i号圆的圆心在(xi,yi)半径ri,求所有最外层,不包含在其他圆内部的圆  //如果用圆心检测的话复杂度为O(N*N)  //平面扫描技术可以降低算法的复杂度,就是查看当前扫面线经过的圆左侧的时候,Y坐标上相邻最近的两个圆  #include <cstdio.h>#include <iostream>  #include <algorithm>  #include <vector>  #include <set>  #include <utility>  using namespace std;  #define  MAX_N 40006  static int N;  static double x[MAX_N],y[MAX_N],r[MAX_N];    //判断圆i是否在圆j的内部  static bool inside(int i,int j){      double dx =x[i] - x[j],dy = y[i] - y[j];      return dx*dx + dy*dy <=r[j]*r[j];  }    //枚举关键点  static void solve(){      vector<pair<double,int> >events;//圆的左右两端的x坐标      for (int i=0;i<N;++i)      {          events.push_back(make_pair(x[i]-r[i],i));          events.push_back(make_pair(x[i]+r[i],i+N));      }      sort(events.begin(),events.end());        //平面扫描      //注意有个特殊情况:    //就是新要插入的点,如果纵坐标,和set内部的某个正在集合中的圆的坐标相等,那么一定有这个新圆在其内部    set<pair<double,int> >outers;//与扫描线相交的最外层圆的集合      vector<int>res;//最外层的圆列表      for (int i=0;i<events.size();++i)      {          int id = events[i].second%N;          if (events[i].second<N)//扫描的左端          {              set<pair<double,int> >::iterator it  = outers.lower_bound(make_pair(y[id],id));              if (it!=outers.end()&&inside(id,it->second))               continue;              if (it!=outers.begin()&&inside(id,(--it)->second))               continue;              res.push_back(id);              outers.insert(make_pair(y[id],id));          }          else              outers.erase(make_pair(y[id],id));      }        sort(res.begin(),res.end());      printf("%d\n",res.size());      for (int i=0;i<res.size();++i)      {          printf("%d%c",res[i]+1,i+1==res.size()?'\n':' ');      }  }        int main(){      scanf("%d",&N);      for (int i=0;i<N;++i)      {          scanf("%lf %lf %lf",&r[i],&x[i],&y[i]);      }      solve();        return 0;  }  


0 0
原创粉丝点击