zoj 3272 || hdu 3264 Open-air shopping malls(1Y哦~~哈哈哈哈~)

2009 Asia Ningbo Regional Contest 。。。2009GB他们参加的那个区域赛的计算几何题~

给你N个圆,求一个圆,圆心在这个N个圆的其中一个圆心上,使得半径 r 可以覆盖到所有的圆使得所有圆的覆盖面积大于它自身的一半。求这个最小的半径。

分析可知,当正好覆盖到某个圆的一半的时候,这个半径最小。

因为圆最多才20个,所以枚举圆心,对于每个圆心,二分半径,最终确定最小半径即可。对于每个圆心,最小半径肯定是大于离它最近的圆的圆心距,最大的一定是小于离它最远的圆的圆心距+那个圆的半径。

如果有一个圆覆盖的面积比一半小,那么说明这个半径小了,如果都比一半大,说明这个半径大了,有一个正好说明这个半径可取~

刚搜了下,基本都是这个做法。。。

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG puts("here!!!")

using namespace std;

const int MAX = 25;
const double inf = 1e30;
const double pi = acos(-1.0);

struct point { double x,y;};
struct circle
{
	point c;
	double r;
	double area()
	{
		return pi*r*r;
	};
};

circle c[MAX];

const double eps = 1e-6;
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == y
double disp2p(point a,point b) //  a b 两点之间的距离 
{
	return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) );
}
bool c2c_sep(point c1,double r1,point c2,double r2)
{
	return dy(disp2p(c1,c2), r1 + r2);
}
double gongxing_area(double r1,double r2,double l) // 两圆半径以及连心线长度 
{
    double cosaa = (r1*r1 + l*l - r2*r2)/(2*r1*l);      // cos值   
    double fcosaa = acos(cosaa)*2;      				//夹角   
    double Shu = fcosaa*r1*r1/2;        	  			// 扇形面积   
    double Ssan = r1*r1*sin(fcosaa)/2;  				// 三角形面积   
    return (Shu - Ssan);                				//扇形面积减去三角形面积  
}
bool c2c_ainb(point a,double r1,point b,double r2)
{
	return xy(disp2p(a,b),r2 - r1);	//a在b中,如果是包括内切,用xyd 
}
double c2c_inst_area(point a,double r1,point b,double r2)
{
	if( c2c_ainb(a,r1,b,r2) )	return pi*r1*r1;	// a内含于b 
	if( c2c_ainb(b,r2,a,r1) )	return pi*r2*r2;	// b内含于a 
	double l = disp2p(a,b);				// 如果单纯求相交面积,需判断相交,从这儿到下面这段 
	return gongxing_area(r1,r2,l) + gongxing_area(r2,r1,l);
}
int compute(point c,double r, int n,circle *cc)
{
	int flag = 0;
	for(int i=0; i<n; i++)
	{
		if( c2c_sep(c, r, cc[i].c, cc[i].r) )
			return -1;
		double inst_area = c2c_inst_area(c, r, cc[i].c, cc[i].r);
		if( xy(inst_area*2, cc[i].area()) )
			return -1;
		if( dd(inst_area*2, cc[i].area()) )
			flag = 1;
	}
	if( flag == 0 ) return 1;
	return 0;
}

double circle_r(int x,int n)
{
	double minr = inf,maxr = 0;
	for(int i=0; i<n; i++)
	{
		if( i == x ) continue;
		double len = disp2p(c[i].c, c[x].c);
		if( dy(len + c[i].r, maxr) )
			maxr = len + c[i].r;
		if( xy(len, minr) )
			minr = len;
	}
	double begin = minr, end = maxr;
	
	while( begin != end )
	{
		double mid = (begin + end) / 2.0;
		int flag = compute(c[x].c, mid, n, c);
		if( flag == 0 ) return mid;
		if( flag == 1 )
			end = mid;
		else
			begin = mid;
	}
	return -1;
}

	 
double solve(int n)
{
	double r = inf;
	for(int i=0; i<n; i++)
	{
		double ans = circle_r(i,n);
		if( xy(ans,r) ) r = ans;
	}
	return r;
}
int main()
{
	int n,ncases;
	
	scanf("%d",&ncases);
	
	while( ncases-- )
	{
		scanf("%d", &n);
		for(int i=0; i<n; i++)
			scanf("%lf%lf%lf", &c[i].c.x, &c[i].c.y, &c[i].r);
		
		if( n == 1 )
		{
			printf("%.4lf\n",sqrt(c[0].r*c[0].r/2));
			continue;
		}
		double ans = solve(n);
		
		printf("%.4lf\n",ans);
		
	}

return 0;
}


你可能感兴趣的:(c,struct)