[洛谷P3829][SHOI2012]信用卡凸包

题目大意:有$n$张一模一样的信用卡,每个角进行了圆滑处理,问这些卡组成的“凸包”的周长

题解:发现是圆滑处理的圆心围成的凸包加上一个圆周即可

卡点:输入长宽弄反,然后以为是卡精

 

C++ Code:

#include <algorithm>
#include <cstdio>
#include <cmath>
#include <iomanip>
#include <iostream>
#define maxn 10010
const double Pi = acosl(-1);

struct Point {
	long double x, y;
	Point() { }
	Point(long double __x, long double __y) : x(__x), y(__y) { }

	inline long double operator ^ (const Point &rhs) const {
		return x * rhs.y - y * rhs.x;
	}
	inline Point operator + (const Point &rhs) const {
		return Point(x + rhs.x, y + rhs.y);
	}
	inline Point operator - (const Point &rhs) const {
		return Point(x - rhs.x, y - rhs.y);
	}
	inline Point rotate(long double theta) {
		const long double Sin = sinl(theta), Cos = cosl(theta);
		return Point(x * Cos - y * Sin, x * Sin + y * Cos);
	}
} s[maxn << 2], O, v[maxn << 2];
inline long double abs2(const Point &x) { return x.x * x.x + x.y * x.y; }
inline long double dis(const Point &lhs, const Point &rhs) { return sqrtl(abs2(lhs - rhs)); }
inline long double det(const Point &O, const Point &lhs, const Point &rhs) {
	return (lhs - O) ^ (rhs - O);
}
inline bool cmp(const Point &x, const Point &y) {
	static Point X, Y; X = x - O, Y = y - O;
	static long double tmp; tmp = X ^ Y;
	return (tmp > 0) || (tmp == 0 && abs2(X) < abs2(Y));
}

int n, tot;
long double ans, A, B, R;
int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	std::cin >> n >> A >> B >> R; ans = 2 * R * Pi;
	A /= 2, B /= 2, A -= R, B -= R;
	for (int i = 0; i < n; ++i) {
		static long double x, y, theta;
		std::cin >> x >> y >> theta;
		const Point t1 = Point(B, A).rotate(theta), t2 = Point(B, -A).rotate(theta), O(x, y);
		s[tot++] = O - t1, s[tot++] = O + t1;
		s[tot++] = O - t2, s[tot++] = O + t2;
	}
	int miny = 0;
	for (int i = 0; i < tot; ++i)
		if (s[i].y < s[miny].y || (s[i].y == s[miny].y && s[i].x < s[miny].x)) miny = i;
	std::swap(s[0], s[miny]); O = s[0];
	std::sort(s + 1, s + tot, cmp);
	n = tot, tot = 3;
	v[0] = s[0], v[1] = s[1], v[2] = s[2];
	for (int i = 3; i < n; ++i) {
		Point *a = v + tot - 2, *b = v + tot - 1;
		while (tot > 2 && det(*a, *b, s[i]) <= 0) {
			--tot, --a, --b;
		}
		v[tot++] = s[i];
	}
	for (int i = 1; i < tot; ++i) ans += dis(v[i - 1], v[i]);
	ans += dis(v[0], v[tot - 1]);
	std::cout << std::fixed << std::setprecision(2) << ans << '\n';
	return 0;
}

  

转载于:https://www.cnblogs.com/Memory-of-winter/p/10361478.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值