写得有点圡
水平排序版本:
#include <cmath> #include <cstdio> #include <algorithm> #include <iostream> using namespace std; struct point{ double x,y; bool operator < (point &a){ return y<a.y || (y == a.y && x<a.x); } }; bool mult(point &sp,point &ep,point &op){ return (sp.x-op.x)*(ep.y-op.y) >=(ep.x-op.x)*(sp.y-op.y); } double dist(point &a,point &b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double graham(point *pnt,int n,point res[]){ int i,len,k=0,top=1; sort(pnt,pnt+n); if(n==0) return 0; res[0]=pnt[0]; if(n==1) return 0; res[1]=pnt[1]; if(n==2) return dist(pnt[0],pnt[1]); res[2]=pnt[2]; for(i=2;i<n;i++){ while(top && mult(pnt[i],res[top],res[top-1])) //左转退栈,上凸包 top--; res[++top]=pnt[i]; } len=top; res[++top]=pnt[n-2]; for(i=n-3;i>=0;i--){ while(top!=len && mult(pnt[i],res[top],res[top-1]))//下凸包。 top--; res[++top]=pnt[i]; } double area=0; for(i=1;i<=top;i++){ area+=dist(res[i],res[(i+1)>top?1:(i+1)]); } return area; } int main(){ int n; point pnt[105],res[105]; while(scanf("%d",&n) && n){ for(int i=0;i<n;i++) scanf("%lf %lf",&pnt[i].x,&pnt[i].y); printf("%.2lf\n",graham(pnt,n,res)); } return 0; }
极角排序版本:
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <algorithm> using namespace std; typedef struct point{ double x,y; bool operator < (point &a){ return y<a.y || (y==a.y && x<a.y); //重载小于号 } }p; p temp; double dist(p &a,p &b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } bool cmp(p &a,p &b){ double xmt=(a.x-temp.x)*(b.y-temp.y)-(b.x-temp.x)*(a.y-temp.y); if(xmt) //向量不共线就按逆时针旋转 return xmt>0; return dist(a,temp)>dist(b,temp);//向量共线取最长的。 } bool xmult(p& a,p& b,p& t){ //叉乘大于0 往左转,叉乘小于0往右转,等于0向量共线 return (a.x-t.x)*(b.y-t.y)>=(b.x-t.x)*(a.y-t.y); } void swap(p& a,p &b){ temp=b; b=a; a=temp; } double graham(p *pnt,int n,p *res){ //Graham扫描法 if(n==1) return 0; if(n==2) return dist(pnt[0],pnt[1]); int top=-1; for(int i=0;i<n;i++){ while(top>1 && xmult(pnt[i],res[top],res[top-1])) top--; res[++top] = pnt[i]; } double dis=0; for(int j=0;j<=top;j++){ dis+=dist(res[j],res[(j+1)%(top+1)]); } return dis; } int main(){ int n; p pnt[105],res[105]; while(scanf("%d",&n) && n){ int t; for(int i=0;i<n;i++){ scanf("%lf %lf",&pnt[i].x,&pnt[i].y); if(!i || pnt[i]<pnt[t]) //找出最小y坐标值并且最靠左的点 t=i; } swap(pnt[0],pnt[t]); sort(pnt+1,pnt+n,cmp); printf("%.2lf\n",graham(pnt,n,res)); } return 0; }