[CF613A Peter and Snow Blower] 题解

本文介绍了如何使用向量方法解决编程竞赛中的一道题目,涉及计算定点到线段的距离以及求解多边形扫过的圆环面积。通过点乘和叉乘运算判断点是否在线段上,并计算点到直线的距离,最终确定多边形的最小和最大半径,从而得出面积差。
摘要由CSDN通过智能技术生成

[CF613A Peter and Snow Blower] 题解

来水一篇向量题解

第一眼一看:多边形扫过的面积不就是个圆环吗,不就记录个定点到每个点的长度的最值吗 r m a x , r m i n r_{max},r_{min} rmax,rmin 然后答案就是 π ( r m a x 2 − r m i n 2 ) \pi(r_{max}^2-r_{min}^2) π(rmax2rmin2) ,交上去: Wrong answer on test 3 \text{Wrong answer on test 3} Wrong answer on test 3直接爆粗口

经过 n n n 分钟后突然意识到貌似还要看看定点到每条边(注意:边是条线段,不是直线)的距离诶

前置芝士:点乘,叉乘

下面主要讲如何计算定点到线段的距离

(先放一张图)

  1. 如何判 D D D 是否在线段 B C BC BC

很明显:只要 ∠ B , ∠ C < π 2 \angle B, \angle C < \frac{\pi}{2} B,C<2π 就可以了,由于算角度精度较低,所以就有了点积的方法:

构造向量 B A ⃗ , B C ⃗ \vec{BA}, \vec{BC} BA ,BC 如果 B A ⃗ ⋅ B C ⃗ ≥ 0 \vec{BA}\cdot\vec{BC} \ge 0 BA BC 0 D D D 在线段 B C BC BC 上,反之不然。

  1. 如何算 A A A B C BC BC 的距离

(稍微吐槽直线方程亿秒钟,差点没算 s 我)

由于二维的向量叉积可以表示向量组成的平行四边形的面积,而平行四边形的面积有等于 A D × B C AD\times BC AD×BC B C BC BC 可以用两点距离公式算出来,于是这道题就解决了。

贴上代码

double pi = acos(-1);
struct point {
	double x, y;
	point(double _x = 0, double _y = 0)
		: x(_x), y(_y) {}
	inline void read() {
		cin >> x >> y;
	}
	inline friend double dist(point a, point b) {//两点距离公式
		double sq1 = (a.x - b.x), sq2(a.y - b.y);
		return sqrt(sqr(sq1) + sqr(sq2));
	}
	inline friend bool operator==(point a, point b) {
		return a.x == b.x && a.y == b.y;
	}
	inline friend bool operator!=(point a, point b) {
		return a.x != b.x || a.y != b.y;
	}
	inline friend point operator-(point a, point b) {
		return point(a.x - b.x, a.y - b.y);
	}
	inline friend point operator+(point a, point b) {
		return point(a.x + b.x, a.y + b.y);
	}
	inline friend double cross(point a, point b) {//叉乘的坐标运算
		return a.x * b.y - a.y * b.x;
	}
	inline friend double dot(point a, point b) {//点乘的坐标运算
		return a.x * b.x + a.y * b.y;
	}
	inline friend point operator*(point a, double b) {
		return point(a.x * b, a.y * b);
	}
};
double dist_sqr(point a, point b) {//两点距离的平方
	return sqr(a.x - b.x) + sqr(a.y - b.y);
}
inline double distl_sqr(point a, point p, point q) {//点到直线
	if (dot(a - q, p - q) < 0 || dot(a - p, q - p) < 0)//$D$ 没在 $BC$ 上
		return dist_sqr(a, p);
	return cross(p - a, q - a) * cross(p - a, q - a) / dist_sqr(p, q);//返回 $cross(p - a, q - a) / dist(p, q)$ 的平方
}
signed main() {
	int n; cin >> n;
	point rt; rt.read();
	vector<point> p(n);
	double maxi = 0, mini = 1e18;//$r_{max}^2$ 和 $r_{min}^2$
	for (int i = 0; i < n; i++)
		p[i].read();
	for (int i = 0; i < n; i++)
		maxi = max(maxi, dist_sqr(p[i], rt)), mini = min(mini, dist_sqr(p[i], rt));
	for (int i = 0; i < n; i++) {
		point a = p[i], b = p[(i + 1) % n];
		mini = min(mini, distl_sqr(rt, a, b));//只需要更新最近点,最远点一定在多边形的定点上
	}
	printf("%.7llf", pi * (maxi - mini));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值