【CF744D】Hongcow Draws a Circle 二分+几何

【CF744D】Hongcow Draws a Circle

题意:给你平面上n个红点和m个蓝点,求一个最大的圆,满足圆内不存在蓝点,且至少包含一个红点。

$n,m\le 10^3$

题解:我们先不考虑半径为inf的情况。显然所求的圆一定是要与某个蓝点相切的。我们可以先枚举这个蓝点,然后二分答案。当半径已知、一个点固定时,圆的可能位置只能是绕着一个点旋转得到的结果,其余的所有点都对应着极角上的一段区间,我们可以将这些区间排序,采用扫描线,看一下是否存在一段区间包含红点且不包含蓝点即可。

但是如果你仔细分析的话你会发现这样的二分是不满足单调性的。不过如果我们一开始不光枚举蓝点,还枚举所有红点,一起进行二分,这样就满足单调性了。

直接做的复杂度是$O(n\log ^2 n)$,会TLE,看了标程加了一些神优化才过~具体见代码。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define pi acos(-1.0)
using namespace std;
typedef long double db;
const db eps=1e-12;
const int maxn=1010;
struct point
{
	db x,y;
	point() {}
	point(db a,db b) {x=a,y=b;}
	point operator + (const point &a) const {return point(x+a.x,y+a.y);}
	point operator - (const point &a) const {return point(x-a.x,y-a.y);}
	db operator * (const point &a) const {return x*a.y-y*a.x;}
	point operator * (const db &a) const {return point(x*a,y*a);}
}p[maxn<<1];
struct line
{
	point p,v;
	line() {}
	line(point a,point b) {p=a,v=b;}
};
struct node
{
	db x;
	int k;
	node() {}
	node(double a,int b) {x=a,k=b;}
}q[maxn<<3];
int n,m,tot;
inline db dis(point a,point b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
db getrange(point a,point b,db R)
{
	db d=dis(a,b)/2;
	return acos(d/R);
}
bool cmp(const node &a,const node &b) {return a.x<b.x;}
inline bool solve(int x,db R)
{
	int i;
	tot=0;
	if(x<=n)	q[++tot]=node(-pi,1),q[++tot]=node(pi,-1);
	else
	{
		for(i=1;i<=n;i++)
		{
			if(dis(p[i],p[x])>R+R-eps)	continue;
			db a=getrange(p[x],p[i],R),b=atan2(p[i].y-p[x].y,p[i].x-p[x].x);
			db c=b-a,d=b+a;
			if(c<-pi)	c+=2*pi;
			if(d>pi)	d-=2*pi;
			if(c<d)	q[++tot]=node(c,1),q[++tot]=node(d,-1);
			else	q[++tot]=node(-pi,1),q[++tot]=node(d,-1),q[++tot]=node(c,1),q[++tot]=node(pi,-1);
		}
	}
	for(i=n+1;i<=n+m;i++)
	{
		if(dis(p[i],p[x])>R+R-eps)	continue;
		db a=getrange(p[x],p[i],R),b=atan2(p[i].y-p[x].y,p[i].x-p[x].x);
		db c=b-a,d=b+a;
		if(c<-pi)	c+=2*pi;
		if(d>pi)	d-=2*pi;
		if(c<d)	q[++tot]=node(c,-10000),q[++tot]=node(d,10000);
		else	q[++tot]=node(-pi,-10000),q[++tot]=node(d,10000),q[++tot]=node(c,-10000),q[++tot]=node(pi,10000);
	}
	sort(q+1,q+tot+1,cmp);
	int tmp=0;
	for(i=1;i<=tot;i++)
	{
		if(tmp>0&&i!=1&&q[i].x>q[i-1].x+eps)	return 1;
		tmp+=q[i].k;
	}
	return 0;
}
inline bool check(db mid)
{
	for(int i=1;i<=n+m;i++)	if(solve(i,mid))	return 1;
	return 0;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd();
	if(m==1)
	{
		puts("-1");
		return 0;
	}
	int i;
	for(i=1;i<=n;i++)	p[i].x=rd(),p[i].y=rd();
	random_shuffle(p+1,p+n+1);
	for(i=1;i<=m;i++)	p[i+n].x=rd(),p[i+n].y=rd();
	random_shuffle(p+n+1,p+m+1);
	db l=0,r,mid;
	for(i=1;i<=n+m;i++)	if(solve(i,l))	//神优化
	{
		r=1e9;
		while(r-l>1e-5)
		{
			mid=(l+r)/2;
			if(solve(i,mid))	l=mid;
			else	r=mid;
		}
	}
	if(l>1e9-1)	puts("-1");
	else	printf("%.18Lf",l);
	return 0;
}

原文地址:https://www.cnblogs.com/CQzhangyu/p/8503717.html

时间: 2024-10-10 01:07:09

【CF744D】Hongcow Draws a Circle 二分+几何的相关文章

uva 11978 - Fukushima Nuclear Blast(二分+几何)

题目链接:uva 11978 - Fukushima Nuclear Blast 二分,圆和多边形面积交.将多边形拆成n份三角形(每两点与圆心构成),计算有向面积.每个三角形和圆的面积分四类讨论. #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> using namespace std; const double

Incircle and Circumcircle(二分+几何)浙大月赛zoj3806(详解版)图

Incircle and Circumcircle Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge A triangle is one the basic shapes in geometry. It's a polygon with three vertices and three sides which are line segments. A triangle with vertices A, B, C is denot

hdu 4033 二分几何

参考:http://blog.csdn.net/libin56842/article/details/26618129 题意:给一个正多边形内点到其他顶点的距离(逆时针给出),求正多边形的边长 二分多边形的边长 根据余弦定理求出A的角度,之后求出所有角度,加起来是否为360,小于则扩大,大于则缩小边 Sample Input 2 3 3.0 4.0 5.0 3 1.0 2.0 3.0 Sample Output Case 1: 6.766 Case 2: impossible 1 #includ

【CF887E】Little Brother 二分+几何

[CF887E]Little Brother 题意:给你n个圆和一条线段,保证圆和圆.圆和线段所在直线不相交,不相切,不包含.求一个过线段两端点的圆,满足不和任何圆相交(可以相切.包含).问圆的最小半径. n<=100000 题解:比较显然的二分题.由于新圆的半径一定在线段的中垂线上,且距离越远半径越大.那么问题就变成了最小化半径到线段的距离. 不难发现,对于每个圆来说,如果新圆不和它相交,那么半径所在的区域会被限定在$(-\infty,a]\bigcup[b,\infty)$里.a和b我们可以

敏捷软件开发:原则、模式与实践——第10章 LSP:Liskov替换原则

第10章 LSP:Liskov替换原则    Liskov替换原则:子类型(subtype)必须能够替换掉它们的基类型(base type). 10.1 违反LSP的情形 10.1.1 简单例子 对LSP的违反导致了OCP的违反: struct Point { double x, y;} public enum ShapeType { square, circle }; public class Shape { private ShapeType type; public Shape(Shape

UVA 11609 - Anne&#39;s game cayley定理

Lily: “Chantarelle was part of my exotic phase.”Bu?y: “It’s nice. It’s a mushroom.”Lily: “It is? That’s really embarrassing.”Bu?y: “Well, it’s an exotic mushroom, if that’s any comfort.”Joss Whedon, "Anne".A little girl whose name is Anne Spetri

LaTeX图片环境 Picture environment

Picture environment If you need to include simple diagrams or figures in your document, the picture environment may be helpful. This article describes circles, lines, and other graphic elements created with LATEX. Contents 1 Introduction 2 Combining

poj 1905Expanding Rods

1 /* 2 二分 + 几何 3 弧长L, 圆半径R, 弧度 q, L=R*q; 4 二分: 弧度(0~PI) 或者 高度(L/2~L) 5 */ 6 #include<cstdio> 7 #include<iostream> 8 #include<cmath> 9 using namespace std; 10 const double PI = acos(-1.0); 11 double L, L1, T, C, R, Q; 12 13 int main(){ 14

安卓自带下拉刷新SwipeRefreshLayout添加上拉刷新功能

在项目里面要用到刷新库,以前都是使用第三方的,不过看到官方出了  SwipeRefreshLayout之后就用SwipeRefreshLayout,但是不知道什么原因官方SwipeRefreshLayout只提供下拉刷新功能,很多时候我们需要上拉刷新功能,所以下载v4源码修改SwipeRefreshLayout,与之相关联的文件有两个分别是SwipeProgressBar,BakedBezierInterpolator把这三个文件拷贝到项目里面,修改一下包名就可以了.如何实现上拉刷新功能,其