URAL 1159. Fence

给你N条线段的长度求能构成面积最大多边形的面积。

可以YY出,这N个点共圆,肯定是凸包。。。(自己证= =。。)

二分半径即可。

有一种情况是,所有共圆的时候,边都在一条直径的一侧,这样的话得特殊考虑。

判断是否是这种类型的话,可以假设最长边的一半为半径,然后求得除最长边的角度和,看是否小于180,如果小于,说明在一侧,二分的时候特殊判断。

卡精度卡死了,中间计算角度用acos过不去,用asin才可以,神马题啊都。。

非独立思考出来的题,囧。。不过确实是好题(被拍飞。。。><。。。)

#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 FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 110;
const double inf = 1e20;
const double pi = acos(-1.0);
double len[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 angle(double len, double r)
{
	return asin(len/2/r)*2;
}
bool check(int n, double r, bool c)
{	
	FOR(i, 0, n)
		if( xyd(2*r, len[i]) )	//  r过小,构不成三角形 
			return true;
			
	double ang1 = angle(len[0], r);
	double ang2 = 0;
	FOR(i, 1, n)
		ang2 += angle(len[i], r);
	
	if( !c )
	{
		if( ang1 + ang2 > 2 * pi )
			return true;
		return false;
	}
	if( ang1 > ang2 )	
		return true;
	return false;
}

double area_triangle(double a,double b,double c)
{
	double p = (a+b+c)/2.0;
	return sqrt(p*(p-a)*(p-b)*(p-c));
}
double area_c(int n, double r)
{
	double area = 0;
	FOR(i, 0, n)
		area += area_triangle(r, r, len[i]);
	return area;
}
	
double solve(int n)
{
	double begin, end, mid;
	begin = len[0]/2;
	end = inf;
	int cnt = 0;
	double ang = 0;
	FOR(i, 1, n)
		ang += angle(len[i], begin);
		
	bool c = xy(ang, pi) ? true : false;	// 是否是所有点都在一条直径的一侧 
	
	while( xyd(begin, end) )
	{
		if( cnt > 1 ) break;
		if( dd(begin, end) )
			cnt++;
		mid = (begin + end)/2;
		bool f = check(n, mid, c);
		if( f )
			begin = mid;
		else
			end = mid;
	}
	double area = area_c(n, mid);
	if( c )
		area -= 2 * area_triangle(len[0], mid, mid);
	return area;
}

int main()
{
	int n;
	double sum;
	
	while( ~scanf("%d", &n) )
	{
		sum = 0;
		FOR(i, 0, n)
			scanf("%lf", &len[i]);
		
		sort(len, len+n, greater<double>() );
		
		FOR(i, 1, n)
			sum += len[i];
		
		if( xyd(sum, len[0]) )
		{
			puts("0.00");
			continue;
		}
		double ans = solve(n);
		printf("%.2lf\n", ans);
	}

return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值