来水一篇向量题解
第一眼一看:多边形扫过的面积不就是个圆环吗,不就记录个定点到每个点的长度的最值吗 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) π(rmax2−rmin2) ,交上去: Wrong answer on test 3 \text{Wrong answer on test 3} Wrong answer on test 3 ,直接爆粗口。
经过 n n n 分钟后突然意识到貌似还要看看定点到每条边(注意:边是条线段,不是直线)的距离诶
前置芝士:点乘,叉乘
下面主要讲如何计算定点到线段的距离
(先放一张图)
很明显:只要 ∠ 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 上,反之不然。
(稍微吐槽直线方程亿秒钟,差点没算 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));
}