第一次做凸包,这道题要特殊考虑下,n=2时的情况,要除以二才行。
我是从最左边的点出发,每次取斜率最大的点,一直到最右边的点。
然后从最左边的点出发,每次取斜率最低的点,一直到最右边的点。
#include<stdio.h> #include<math.h> #include<algorithm> #include<string.h> using namespace std; const double eps=1e-9; struct node { double x,y; }f[105]; bool flag[105]; int n; bool cmp(node a,node b) { return fabs(a.x-b.x)<eps?(a.y<b.y):(a.x<b.x); } double xielv(int a,int b)//求斜率 { return (f[a].y-f[b].y)/(f[a].x-f[b].x); } double dis(int a,int b)//求距离 { double xx=f[a].x-f[b].x,yy=f[a].y-f[b].y; return sqrt(xx*xx+yy*yy); } void calans()//计算最短周长 { int i,j,now=0,maxi; double ans=0; while(1) { double max=-4000000;//斜率最大值 maxi=now; for(i=1;i<n;i++) { if(flag[i])continue; if(-f[i].x+f[now].x>eps)continue;//在当前点的左边,不考虑 if(fabs(f[now].x-f[i].x)<eps) { if(f[now].y>f[i].y)//在当前点的正下方,不考虑 continue; maxi=i; break; } else { double p=xielv(now,i); if(p>max) { maxi=i; max=p; } } } flag[maxi]=1; ans+=dis(now,maxi); if(maxi==now) { flag[maxi]=0;//最后右边的点要计算两次,去除标记 break; } now=maxi; } now=0; while(1)//每次取斜率最小的点 { double min=4000000; int mini=now; for(i=1;i<n;i++) { if(flag[i])continue; if(-f[i].x+f[now].x>eps)continue;//在当前点的左边,不考虑 if(fabs(f[i].x-f[now].x)<eps) { if(f[i].x+0.1<f[n-1].x)//在当前点的正下方,不考虑 continue; mini=i; break; } double p=xielv(now,i); if(p<min) { mini=i; min=p; } } ans+=dis(now,mini); flag[mini]=1; if(mini==now) break; now=mini; } if(n==2)ans/=2;//n=2时,除以二 printf("%.2f ",ans); } int main() { int i,j; while(scanf("%d",&n)!=-1&&n) { memset(flag,0,sizeof(flag)); for(i=0;i<n;i++) scanf("%lf%lf",&f[i].x,&f[i].y); sort(f,f+n,cmp); calans(); } return 0; }