poj1113

继续来点技能树了。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;
} 

猜你喜欢

转载自blog.csdn.net/qq_38759433/article/details/81736722