poj2932

//平面上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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值