分析:给n个点,求出把所有点包围进去的所有边的和。
计算凸包的步骤:
平面上三个点:p1(x1,y1),p2(x2,y2),p3(x3,y3)
s(p1,p2,p3)=(x1-x3)*(y2-y3)-(x2-x3)*(y1-y3)
如果s>0 则说明 这连接这3个点时是按照逆时针的顺序,如果是s<0则说明连接这3个点是按照顺时针的顺序
1、排序:先按y从小到大排序,y相等时,按x从下到大排序。
bool cmp(node a,node b) { if(a.y==b.y) return a.x<b.x; return a.y<b.y; } 2、判断n是否大于3(小于3围不成凸多边形),然后对初始三个点赋值。 if(n==1) return 0; if(n==2) return dist(ans[0],ans[1]); res[0]=ans[0]; res[1]=ans[1]; res[2]=ans[2]; 3、逆时针方向计算,先从右半边开始算,从第2个点开始,如果新加入的点,与之前确定点的向量的叉乘小于0的话,说明该点在之前的点的右面,不满足凸包,所以删除之前确定的点,top-- for(i=2;i<n;i++){ while(top && mult(ans[i],res[top],res[top-1])) //左转退栈,上凸包 top--; res[++top]=ans[i]; }4、再从左半边开始算,从第2个点开始,如果新加入的点,与之前确定点的向量的叉乘小于0的话,说明该点在之前的点的左,不满足凸包,所以删除之前确定的点,top--
for(i=n-3;i>=0;i--){ while(top!=len && mult(pnt[i],res[top],res[top-1]))//下凸包。 top--; res[++top]=pnt[i]; } 5、向量叉乘函数 bool mult(node a,node b,node t) { return (a.x-t.x)*(b.y-t.y)>=(b.x-t.x)*(a.y-t.y); } AC代码如下: #include <stdio.h> #include <algorithm> #include <math.h> using namespace std; struct node{ int x,y; }ans[105]; bool cmp(node a,node b) { if(a.y==b.y) return a.x<b.x; return a.y<b.y; } double dist(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)); } bool mult(node a,node b,node t) { return (a.x-t.x)*(b.y-t.y)>=(b.x-t.x)*(a.y-t.y); } double grahum(int n) { int len,i,j,k,top=1; node res[105]; sort(ans,ans+n,cmp); if(n==1) return 0; if(n==2) return dist(ans[0],ans[1]); res[0]=ans[0]; res[1]=ans[1]; res[2]=ans[2]; for(i=2;i<n;i++){ while(top && mult(ans[i],res[top],res[top-1])) //左转退栈,上凸包 top--; res[++top]=ans[i]; } len = top; res[++top]=ans[n-2]; for(i=n-3;i>=0;i--){ while(top!=len && mult(ans[i],res[top],res[top-1]))//下凸包。 top--; res[++top]=ans[i]; } double result=.0; for(i=1;i<=top;i++) { result+=dist(res[i],res[(i+1)>top?1:(i+1)]); } return result; } int main() { int n; int i,j; while(scanf("%d",&n),n) { for(i=0;i<n;i++) scanf("%d %d",&ans[i].x,&ans[i].y); printf("%.2lf\n",grahum(n)); } return 0; }
