2020.6.30
下午不想动脑子了,干脆来学习一下计算几何。果然写数据结构就是爽,不用怎么动脑子就行。这个graham扫描法oi考得其实并不算很多,倒是acm一天到晚考这个东西。去年去p大大概听郭神讲过这个,就是排序完不断寻找叉积大于0(向外拐)的上凸壳,然后同样方法扫一遍下凸包就行,听说会被卡成n方,不过我觉得icpc的命题组还是可以信赖的,学了再说。新队友tg2=,没办法计算几何只能我来抗了。这个算法不是很难,我对一些能优化的地方优化了一下,就是可能这样一来常数有点大了。但是绝对好懂,了解过这个算法大概的步骤的一看我的代码应该就懂了,我是把能封装的东西全部封装了一遍,为了可读性,用了工厂模式和typedef把vector和point公用一个结构体,虽然本身也就是一样,但是这样一来可读性属实增加了不少,看代码吧。就是进栈出栈。
代码:
#include <bits/stdc++.h>
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-6
#define FASTIO ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 988244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
ll sign = 1, x = 0;char s = getchar();
while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
return x * sign;
}//快读
void write(ll x){
if(x < 0) putchar('-'),x = -x;
if(x / 10) write(x / 10);
putchar(x % 10 + '0');
}
struct point{
double x,y;
point(double _x = 0.00,double _y = 0.00):x(_x), y(_y){}
double operator^(const point &rhs)const {
return x * rhs.y - y * rhs.x;//叉积顺时针大于0,平行等于0,逆时针小于0
}//叉积
static point make_vector(point p1, point p2){
return point(p2.x - p1.x,p2.y - p1.y );
}
bool operator<(const point &p2)const{
return y == p2.y ? x < p2.x : y < p2.y;
}
}a[limit];
double sq(double i){
return i * i;
}
double dist(point x , point y){
return sqrt(sq(x.x - y.x) + sq(x.y - y.y));//求欧几里得距离
}
int n;
point stk[limit];
int top;
typedef point vect;
int main() {
#ifdef LOCAL
FOPEN;
#endif
n = read();
top = 0;
rep(i ,1, n){
double x, y;
scanf("%lf%lf" , &x, &y);
a[i].x = x, a[i].y = y;
}
sort(a + 1, a + 1 + n);
stk[++top] = a[1] , stk[++top] = a[2];
rep(i ,3, n){
vect u = point::make_vector(stk[top - 1] , stk[top]);
vect v = point::make_vector(stk[top], a[i]);
while (top > 1 && (u ^ v) < 0){
--top;
u = point::make_vector(stk[top - 1] , stk[top]);
v = point::make_vector(stk[top], a[i]);
}
stk[++top] = a[i];
}//上凸包
int threshold = top;
stk[++top] = a[n] , stk[++top] = a[n - 1];
per(i ,1,n - 2){
vect u = point::make_vector(stk[top - 1] , stk[top]);
vect v = point::make_vector(stk[top], a[i]);
while (top > threshold + 1 && (u ^ v) < 0){
--top;
u = point::make_vector(stk[top - 1] , stk[top]);
v = point::make_vector(stk[top], a[i]);
}
stk[++top] = a[i];
}
double ans = 0.0;
rep(i ,1, top - 1){
ans += dist(stk[i], stk[i + 1]);
}
printf("%.2lf" , ans);
return 0;
}