BZOJ4642 泡泡

博客介绍了如何使用扫描线算法处理圆不相交的问题。在插入和删除操作中判断相邻圆是否相切,并通过证明确认该方法可行。在实现扫描线算法时,特别关注了比较函数中相等条件的处理。
摘要由CSDN通过智能技术生成

这题……一看圆不相交,直观上可以扫描线,每次插入和删除的时候判一下相邻的是否相切,然后……大概证一下,好像可以扫描线,然后写一发A了,发现确实可以扫描线……

注意写扫描线的比较函数的时候考虑各种相等情况

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 500010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct cir{
	double x;
	double y;
	double r;
};
struct evt{
	double x;
	int bel;
	int c;
	friend bool operator <(evt x,evt y){
		return fabs(x.x-y.x)>eps?x.x<y.x:x.c<y.c;
	}
};
cir c[MAXN];
struct pt{
	int bel;
	int cl;
	pt(){
		
	}
	pt(int _bel,int _cl){
		bel=_bel;
		cl=_cl;
	}
	double y();
	friend bool operator <(pt x,pt y){
		return x.bel==y.bel?x.cl<y.cl:fabs(x.y()-y.y())>eps?x.y()<y.y():c[x.bel].y!=c[y.bel].y?c[x.bel].y<c[y.bel].y:x.bel<y.bel;
	}
};
int X;
evt e[MAXN*2];
set<pt>wzh;
int n,tot;
map<int,bool>nt[MAXN];
double pt::y(){
	if(cl){
		return ::c[bel].y+sqrt(::c[bel].r*::c[bel].r-(X-::c[bel].x)*(X-::c[bel].x));
	}else{
		return ::c[bel].y-sqrt(::c[bel].r*::c[bel].r-(X-::c[bel].x)*(X-::c[bel].x));
	}
}
int main(){
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r);
	}
	for(i=1;i<=n;i++){
		e[++tot].x=c[i].x-c[i].r;
		e[tot].bel=i;
		e[tot].c=0;
		e[++tot].x=c[i].x+c[i].r;
		e[tot].bel=i;
		e[tot].c=1;
	}
	sort(e+1,e+tot+1);
	for(i=1;i<=tot;i++){
		X=e[i].x;
		if(e[i].c==0){
			set<pt>::iterator p=wzh.insert(pt(e[i].bel,0)).first;
			if(p!=wzh.begin()){
				p--;
				pt x=*p;
				p++;
				pt y=pt(e[i].bel,0);
				if(fabs((c[x.bel].x-c[y.bel].x)*(c[x.bel].x-c[y.bel].x)+(c[x.bel].y-c[y.bel].y)*(c[x.bel].y-c[y.bel].y)-(c[x.bel].r+c[y.bel].r)*(c[x.bel].r+c[y.bel].r))<eps){
					nt[x.bel][y.bel]=1;
					nt[y.bel][x.bel]=1;
				}
			}
			if(p!=(--wzh.end())){
				pt x=*(++p);
				pt y=pt(e[i].bel,0);
				if(fabs((c[x.bel].x-c[y.bel].x)*(c[x.bel].x-c[y.bel].x)+(c[x.bel].y-c[y.bel].y)*(c[x.bel].y-c[y.bel].y)-(c[x.bel].r+c[y.bel].r)*(c[x.bel].r+c[y.bel].r))<eps){
					nt[x.bel][y.bel]=1;
					nt[y.bel][x.bel]=1;
				}
			}
			wzh.insert(pt(e[i].bel,1));
		}
		if(e[i].c==1){
			wzh.erase(pt(e[i].bel,1));
			set<pt>::iterator p=wzh.find(pt(e[i].bel,0));
			if(p!=wzh.begin()&&(p!=--wzh.end())){
				pt x=*(--p);
				p++;
				pt y=*(++p);
				if(fabs((c[x.bel].x-c[y.bel].x)*(c[x.bel].x-c[y.bel].x)+(c[x.bel].y-c[y.bel].y)*(c[x.bel].y-c[y.bel].y)-(c[x.bel].r+c[y.bel].r)*(c[x.bel].r+c[y.bel].r))<eps){
					nt[x.bel][y.bel]=1;
					nt[y.bel][x.bel]=1;
				}
			}
			wzh.erase(pt(e[i].bel,0));
		}
	}
	int ans=0;
	for(i=1;i<=n;i++){
		ans+=nt[i].size();
	}
	printf("%d\n",ans/2);
	return 0;
}

/*
7
0 0 1
2 0 1
4 0 1
6 0 1
0 2 1
0 4 1
0 6 1

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值