【bzoj2829】信用卡凸包 凸包

题目描述

输入

输出

样例输入

2
6.0 2.0 0.0
0.0 0.0 0.0
2.0 -2.0 1.5707963268

样例输出

21.66


题解

凸包

傻逼题,答案显然为:所有圆心构成的凸包周长+一个圆的周长。这里求凸包用的方法是求上下两个凸壳再拼起来。

时间复杂度为排序的 $O(n\log n)$ 

我才不会告诉你puts("nan:)可以过呢

#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const double pi = acos(-1);
struct data
{
	double x , y;
	data() {}
	data(double a , double b) {x = a , y = b;}
	data operator-(const data &a)const {return data(x - a.x , y - a.y);}
	double operator*(const data &a)const {return x * a.y - y * a.x;}
	bool operator<(const data &a)const {return x == a.x ? y < a.y : x < a.x;}
}p[40010] , sa[40010] , sb[40010];
int ta , tb;
inline double dis(data a , data b)
{
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int main()
{
	int n , i , m = 0;
	double a , b , r , x , y , c , ans = 0;
	scanf("%d%lf%lf%lf" , &n , &a , &b , &r) , a = a / 2 - r , b = b / 2 - r;
	for(i = 1 ; i <= n ; i ++ )
	{
		scanf("%lf%lf%lf" , &x , &y , &c);
		p[++m] = data(x + b * cos(c) + a * sin(c) , y + b * sin(c) - a * cos(c));
		p[++m] = data(x - b * cos(c) + a * sin(c) , y - b * sin(c) - a * cos(c));
		p[++m] = data(x + b * cos(c) - a * sin(c) , y + b * sin(c) + a * cos(c));
		p[++m] = data(x - b * cos(c) - a * sin(c) , y - b * sin(c) + a * cos(c));
	}
	sort(p + 1 , p + m + 1);
	for(i = 1 ; i <= m ; i ++ )
	{
		while(ta > 1 && (p[i] - sa[ta]) * (sa[ta - 1] - sa[ta]) >= 0) ta -- ;
		while(tb > 1 && (p[i] - sb[tb]) * (sb[tb - 1] - sb[tb]) <= 0) tb -- ;
		sa[++ta] = sb[++tb] = p[i];
	}
	for(i = 1 ; i < ta ; i ++ ) ans += dis(sa[i] , sa[i + 1]);
	for(i = 1 ; i < tb ; i ++ ) ans += dis(sb[i] , sb[i + 1]);
	printf("%.2lf\n" , ans + dis(sa[1] , sb[1]) + dis(sa[ta] , sb[tb]) + 2 * pi * r);
	return 0;
}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/8565265.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值