初三都毕业了还不会计算几何,真TM蛋痛。
不过事实证明计算几何都是送命题,去死磕一不小心就翻车了,考场时还是要谨慎点。
二维凸包定义:
一个二维平面上有一些点,现在要求一个凸多边形,使它的顶点在这些点上,且这个凸多边形的内部(包括边上)包括了所有的点。
构建二维凸包:
首先找到一个一定在凸包上的点,那么找这些点中最下的点(如果y相同取x最小的)就行了。
然后极角排序(不用求出角,叉积判正负即可)。
接着单调栈,也是用叉积判正负即可。
注意精度误差。
裸题:
【SHTSC2012day1】信用卡凸包
Code:
#include<cmath>
#include<cstdio>
#include<algorithm>
#define db double
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define abs(a) ((a) > 0 ? (a) : -(a))
using namespace std;
const db pi = acos(-1), eps = 1e-8;
struct P {
db x, y;
P(db _x = 0, db _y = 0) {x = _x, y = _y;}
};
P operator +(P a, P b) {return P(a.x + b.x, a.y + b.y);}
P operator -(P a, P b) {return P(a.x - b.x, a.y - b.y);}
P operator *(P a, db b) {return P(a.x * b, a.y * b);}
db operator ^(P a, P b) {return a.x * b.y - a.y * b.x;}
P operator *(P a, P b) {return P(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);}
P angle(db x) {return P(cos(x), sin(x));}
P rotate(P a, db x) {return a * angle(x);}
db len(P a) {return sqrt(a.x * a.x + a.y * a.y);}
db dis(P a, P b) {return len(a - b);}
const int N = 1e5 + 5;
int n, m, z0, u, z[N]; db a, b, r, x, y, theta;
P d[N];
int cmp(P a, P b) {
return ((a - d[1]) ^ (b - d[1])) + eps >= 0;
}
int main() {
scanf("%d %lf %lf %lf", &n, &a, &b, &r);
fo(i, 1, n) {
scanf("%lf %lf %lf", &x, &y, &theta);
d[++ m] = rotate(P(- b / 2 + r, - a / 2 + r), theta) + P(x, y);
d[++ m] = rotate(P(b / 2 - r, - a / 2 + r), theta) + P(x, y);
d[++ m] = rotate(P(- b / 2 + r, a / 2 - r), theta) + P(x, y);
d[++ m] = rotate(P(b / 2 - r, a / 2 - r), theta) + P(x, y);
}
u = 1;
fo(i, 2, m) if(d[i].y < d[u].y || (abs(d[i].y - d[u].y) <= eps && d[i].x - eps < d[u].x))
u = i;
swap(d[1], d[u]);
sort(d + 2, d + m + 1, cmp);
z[z0 = 1] = 1; z[z0 = 2] = 2;
fo(i, 3, m) {
while(z0 > 1 && ((d[i] - d[z[z0 - 1]]) ^ (d[z[z0]] - d[z[z0 - 1]])) + eps >= 0)
z0 --;
z[++ z0] = i;
}
db ans = 2 * r * pi;
fo(i, 2, z0) ans += dis(d[z[i]], d[z[i - 1]]);
ans += dis(d[z[1]], d[z[z0]]);
printf("%.2lf", ans);
}