POJ 3831 Open-air shopping malls

题目大意:

题目链接

注释代码:

/*                                                
 * Problem ID : POJ 3831 Open-air shopping malls
 * Author     : Lirx.t.Una                                                
 * Language   : C++                               
 * Run Time   : 0 ms                                                
 * Run Memory : 232 KB                                                
*/ 

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const double	INF		= 1E10;
const int		MAXCIRN = 20;//圆的最大数量

const double	PI  = 3.1415926535897932;
const double	ESP = 1E-8;//精度控制

struct	Cir {

	double		x, y;//圆心坐标
	double		r;//半径

	Cir(void) {}

	Cir( double xx, double yy, double rr ) :
		x(xx), y(yy), r(rr) {}

	friend istream &
	operator>>(istream &is, Cir &cir) {

		is >> cir.x >> cir.y >> cir.r;

		return is;
	}

	double
	POW(double x) {

		return x * x;
	}

	double
	operator^(Cir &oth) {//重载计算两个圆心之间的距离

		return sqrt( POW( x - oth.x ) + POW( y - oth.y ) );
	}

	double
	operator/(Cir &oth) {//求本圆在oth圆中的楔形的面积

		double	a, b, c;
		double	ang;
		double	s1, s2;

		a = r;
		b = (*this) ^ oth;
		c = oth.r;

		ang = 2.0 * acos( ( POW(a) + POW(b) - POW(c) ) / ( 2.0 * a * b ) );//余弦公式求a、b之间的夹角ang
		s1  = POW(a) * ang / 2.0;//求扇形面积
		s2  = POW(a) * sin(ang) / 2.0;//求三角形面积

		return s1 - s2;
	}

	double
	operator*(Cir &oth) {//求重叠区域面积
	
		return (*this) / oth + oth / (*this);
	}

	bool
	operator>(Cir &oth) {//求两者重叠面积是否超过后者的一半
	
		double	dist;

		dist = (*this) ^ oth;

		//如果两圆无重叠
		if ( dist - ( r + oth.r ) > ESP ) return false;

		if ( fabs( r - oth.r )  - dist > ESP )//如果一个包在另一个里面
			if ( r - oth.r > ESP ) return true;//前者包含后者
			else return POW(r) * 2.0 - POW(oth.r) > ESP;//后者包含前者,但是需要检查前者面积是否超过后者一半

		return (*this) * oth * 2.0 - POW(oth.r) * PI > ESP;//否则就是正常的相交了
	}
};

int		n;//圆的数量
Cir		cir[MAXCIRN];//Circle

bool
check(Cir &cc) {//检查圆cc是否和其它所有圆的重叠部分超过各圆面积的一半

	int		i;

	for ( i = 0; i < n; i++ )
		if ( !( cc > cir[i] ) )
			return false;

	return true;
}

int
main() {

	int		t;//测例数
	int		i;//计数变量

	double	lft, rht, mid;//二分搜索

	double	ans;//最终的最小半径

	scanf("%d", &t);
	while ( t-- ) {
	
		scanf("%d", &n);
		for ( i = 0; i < n; i++ ) cin >> cir[i];

		ans = INF;
		for ( i = 0; i < n; i++ ) {//对每个位置逐个枚举

			lft = 0;
			rht = 50000;//二分最大断点

			while ( rht - lft > 1E-6 ) {//二分精度

				Cir	cc( cir[i].x, cir[i].y, mid = ( lft + rht ) / 2.0);

				if ( check(cc) ) rht = mid;
				else lft = mid;
			}

			ans = min( ans, ( lft + rht ) / 2.0 );//更新每一个位置的结果对ans的改变
		}

		printf("%.4lf\n", ans);
	}

	return 0;
}
无注释代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const double	INF		= 1E10;
const int		MAXCIRN = 20;

const double	PI  = 3.1415926535897932;
const double	ESP = 1E-8;

struct	Cir {

	double		x, y;
	double		r;

	Cir(void) {}

	Cir( double xx, double yy, double rr ) :
		x(xx), y(yy), r(rr) {}

	friend istream &
	operator>>(istream &is, Cir &cir) {

		is >> cir.x >> cir.y >> cir.r;

		return is;
	}

	double
	POW(double x) {

		return x * x;
	}

	double
	operator^(Cir &oth) {

		return sqrt( POW( x - oth.x ) + POW( y - oth.y ) );
	}

	double
	operator/(Cir &oth) {

		double	a, b, c;
		double	ang;
		double	s1, s2;

		a = r;
		b = (*this) ^ oth;
		c = oth.r;

		ang = 2.0 * acos( ( POW(a) + POW(b) - POW(c) ) / ( 2.0 * a * b ) );
		s1  = POW(a) * ang / 2.0;
		s2  = POW(a) * sin(ang) / 2.0;

		return s1 - s2;
	}

	double
	operator*(Cir &oth) {
	
		return (*this) / oth + oth / (*this);
	}

	bool
	operator>(Cir &oth) {
	
		double	dist;

		dist = (*this) ^ oth;

		if ( dist - ( r + oth.r ) > ESP ) return false;

		if ( fabs( r - oth.r )  - dist > ESP )
			if ( r - oth.r > ESP ) return true;
			else return POW(r) * 2.0 - POW(oth.r) > ESP;

		return (*this) * oth * 2.0 - POW(oth.r) * PI > ESP;
	}
};

int		n;
Cir		cir[MAXCIRN];

bool
check(Cir &cc) {

	int		i;

	for ( i = 0; i < n; i++ )
		if ( !( cc > cir[i] ) )
			return false;

	return true;
}

int
main() {

	int		t;
	int		i;

	double	lft, rht, mid;

	double	ans;

	scanf("%d", &t);
	while ( t-- ) {
	
		scanf("%d", &n);
		for ( i = 0; i < n; i++ ) cin >> cir[i];

		ans = INF;
		for ( i = 0; i < n; i++ ) {

			lft = 0;
			rht = 50000;

			while ( rht - lft > 1E-6 ) {

				Cir	cc( cir[i].x, cir[i].y, mid = ( lft + rht ) / 2.0);

				if ( check(cc) ) rht = mid;
				else lft = mid;
			}

			ans = min( ans, ( lft + rht ) / 2.0 );
		}

		printf("%.4lf\n", ans);
	}

	return 0;
}

单词解释:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值