//平面上N个两两没有公共点的圆,i号圆的圆心在(xi,yi)半径ri,求所有最外层,不包含在其他圆内部的圆
//如果用圆心检测的话复杂度为O(N*N)
//平面扫描技术可以降低算法的复杂度,就是查看当前扫面线经过的圆左侧的时候,Y坐标上相邻最近的两个圆
#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<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;
}
poj2932
最新推荐文章于 2019-02-20 12:31:44 发布