凸包详解:点击打开链接
#include<stdio.h> #include<algorithm> #include<math.h> using namespace std; const int INF = 50005; struct node { double x,y; }; node data[INF]; node res[INF]; //数组模拟栈(这里如果用stl自带的栈会比较麻烦) int Graham(node* data,node* res, int n); double cross(node a, node b, node mark); //求向量mark->a, 向量mark-> b的叉积; double dis(node a, node b); //求a,b两点距离; long long dis1(node a, node b); bool cmp(node a,node b) { int ans = cross(a,b,data[0]); if(ans > 0 || (ans == 0 && dis(a,data[0]) > dis(b,data[0]))) return true; return false; } int main() { int n; scanf("%d", &n); //点集的大小 for(int i = 0; i < n; i++) scanf("%lf %lf",&data[i].x,&data[i].y); int len = Graham(data,res,n); //凸包的大小(也就是凸包所包含点的数目) long long max = -1; for(int i = 0; i <len; i++) { printf("%lf %lf\n",res[i].x,res[i].y) ; //输出凸包 } return 0; } int Graham(node* data,node* res, int n) { //求出最左下的那个点(原点或参照点),并将此点和data[0]交换一下------------------------- int t = 0; for(int i = 1; i <n; i++) { if(data[t].y > data[i].y || (data[t].y == data[i].y) && data[t].x > data[i].x) t = i; } node temp = data[t]; data[t] = data[0]; data[0] = temp; //将除了data[0]之外的点按与data[0]的极角从小到大排序----------------------- /* 如果用注释的部分来排序会很慢,所以用快排 for(int i = 1; i < n; i++) { int t = i; for(int j =i+1; j < n; j++) { double flag = cross(data[t],data[j],data[0]); if(flag < 0 || ( flag == 0 && dis(data[t],data[0]) > dis(data[j], data[0]) ) ) t = j; } node temp1 = data[t]; data[t] = data[i]; data[i] = temp1; } */ sort(data + 1,data + n,cmp); //初始化栈res---------------------------------------------------------------- res[0] = data[0]; res[1] = data[1]; res[2] = data[2]; int top = 2; //利用栈不断维护凸壳---------------------------------------------------------- for(int i =3; i < n; i++) { while(cross(res[top-1], data[i] ,res[top]) > 0) //找出所有右转的点,然后弹出栈 top--; res[++top] = data[i]; } return top + 1; } double cross(node a, node b, node mark) { return (a.x - mark.x) * (b.y - mark.y) - (b.x - mark.x) * (a.y - mark.y); } double dis(node a, node b) { return sqrt( (a.x -b.x) * (a.x - b.x) - (a.y + b.y) * (a.y - b.y) ); }