#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int Max = 1100; struct Point { int x; int y; }; int num; Point p[Max]; ///原始点集 Point ch[Max]; ///凸包点集 ///p0p1叉乘p0p2 int xmult(const Point &p0, const Point &p1, const Point &p2) { return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y); } double dis(const Point &a, const Point &b) { return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } ///逆时针顺序把极角排序 bool cmp(const Point &a, const Point &b) { int ret = xmult(p[0],a,b); if(ret>0) return true; if(ret==0&&dis(p[0],a)<dis(p[0],b))//保留凸包上的点,共线取最近 return true; return false; } //如果我们只要求保留极点而去除在边上的点 //我们只需在取外侧的点的时候 碰到共线的点取最远的 //相反 如果我们要保留所有在边上的点我们只需要在共线的点中取最近的 /** p: 原始点序列 n: 原始点的个数 ch: 栈,用来保存凸包上的点 top: 凸包上点的个数 */ void Graham(Point *p, int n, Point *ch, int &top) { int i,k=0; for(i=1; i < n; i++)//取纵坐标最小的点,纵坐标相同取横坐标最小,此点必在凸包上 { if(p[k].y>p[i].y || ((p[k].y==p[i].y)&&p[k].x>p[i].x)) k = i; } swap(p[k],p[0]);//p[0]为此点 sort(p+1,p+n,cmp);// top = 0; ch[top++] = p[0]; ch[top++] = p[1]; ch[top++] = p[2]; for(i = 3; i < n; ch[top++]=p[i++]) while(top>=2 && xmult(ch[top-2],ch[top-1],p[i])<0) ///是否向左 top--; } int main() { //freopen("C:\\Users\\Sky\\Desktop\\1.in","r",stdin); int i; int n,l; int t; while(scanf("%d",&n),n) { for(i = 0; i < n; i++) scanf("%d %d",&p[i].x,&p[i].y); if(n==1) { printf("0.00\n"); continue; } else if(n==2) { printf("%.2lf\n",dis(p[0],p[1])); continue; } Graham(p,n,ch,num); double result=0.0; for(i = 0; i < num-1; i++) result += dis(ch[i],ch[i+1]); result += dis(ch[0],ch[num-1]); printf("%.2lf\n",result); } return 0; }
相关文章: