继续来点技能树了。emmm,感觉这个东西挺好理解的,不管是概念还是算法
凸包:首先是一个凸多边形,其次它可以将所有点都包含进来(或者在边上)
算法的话就是按角度不断扫,然后不断更新
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 2e5 + 20;
const double PI = acos(-1.0);
struct point{
int x, y;
}p[N];
int n;
int stack[N], top;
int cross(point p0, point p1, point p2){ //p0p1 * p0p2叉积 判断顺/逆时针
return (p1. x - p0. x) * (p2. y - p0. y) - (p1. y - p0. y) * (p2. x - p0. x);
}
double dis(point p1, point p2){
return sqrt((double)(p2. x - p1. x) * (p2. x - p1. x) + (p2. y - p1. y) * (p2. y - p1. y));
}
bool cmp(point p1, point p2){ //极角排序 p[0]为最下方&&最左边的点
int tmp = cross(p[0], p1, p2);
if(tmp > 0)
return true;
else if(tmp == 0 && dis(p[0], p1) < dis(p[0], p2))
return true;//角度相同,距离小在前
else return false;
}
void Graham(int n){//求凸包
if(n == 1){
top = 0;
stack[0] = 0;
}
if(n == 2){
top = 1;
stack[0] = 0;
stack[1] = 1;
}
if(n > 2){
for(int i = 0; i <= 1; i ++)
stack[i] = i;
top = 1;
for(int i = 2; i < n; i ++){ //O(2n) 求出前i个点集形成的凸包
while(top > 0 && cross(p[stack[top - 1]], p[stack[top]], p[i]) <= 0)
top --;
top ++;
stack[top] = i;
}
}
}
int main(){
double L;
while(cin >> n >> L){
int low = 0;
for(int i = 0; i < n; i ++){
cin >> p[i]. x >> p[i]. y;
if((p[low]. y == p[i]. y && p[low]. x > p[i]. x) || p[low]. y > p[i]. y)
low = i;
}
swap(p[0], p[low]);//p[0]为最下方&&最左边的点
sort(p + 1, p + n, cmp);
Graham(n);
double res = 0;
for(int i = 0; i < top; i ++)
res += dis(p[stack[i]], p[stack[i + 1]]);
res += dis(p[stack[0]], p[stack[top]]);
res += 2 * PI * L;
printf("%d\n", int(res + 0.5));
}
return 0;
}