Graham算法求凸包 PKU1113
来源:互联网 发布:买车下个什么app软件 编辑:程序博客网 时间:2024/05/21 08:00
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<iostream>#include<math.h>#include<algorithm>using namespace std;/* PointSet[]:输入的点集 ch[]:输出的凸包上的点集,按照逆时针方向排列 n:PointSet中的点的数目 len:输出的凸包上的点的个数 */ struct Point { float x,y; }; //小于0,说明向量p0p1的极角大于p0p2的极角 float multiply(Point p1,Point p2,Point p0) { return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y)); } float dis(Point p1,Point p2) { return(sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y))); } void Graham_scan(Point PointSet[],Point ch[],int n,int &len) { int i,j,k=0,top=2; Point tmp; //找到最下且偏左的那个点 for(i=1;i<n;i++) if ((PointSet[i].y<PointSet[k].y)||((PointSet[i].y==PointSet[k].y)&&(PointSet[i].x<PointSet[k].x))) k=i; //将这个点指定为PointSet[0] tmp=PointSet[0]; PointSet[0]=PointSet[k]; PointSet[k]=tmp; //按极角从小到大,距离偏短进行排序 for (i=1;i<n-1;i++) { k=i; for (j=i+1;j<n;j++) if( (multiply(PointSet[j],PointSet[k],PointSet[0])>0) ||((multiply(PointSet[j],PointSet[k],PointSet[0])==0) &&(dis(PointSet[0],PointSet[j])<dis(PointSet[0],PointSet[k]))) ) k=j;//k保存极角最小的那个点,或者相同距离原点最近 tmp=PointSet[i]; PointSet[i]=PointSet[k]; PointSet[k]=tmp; } //第三个点先入栈 ch[0]=PointSet[0]; ch[1]=PointSet[1]; ch[2]=PointSet[2]; //判断与其余所有点的关系 for (i=3;i<n;i++) { //不满足向左转的关系,栈顶元素出栈 while(multiply(PointSet[i],ch[top],ch[top-1])>=0) top--; //当前点与栈内所有点满足向左关系,因此入栈. ch[++top]=PointSet[i]; } len=top+1; } const int maxN=1010; Point PointSet[maxN]; Point ch[maxN]; int n; int len; int main() { double ans=0; int d; cin>>n>>d; for(int i=0;i<n;i++) cin>>PointSet[i].x>>PointSet[i].y;//input the data; Graham_scan(PointSet,ch,n,len); for(int i=0;i<len;i++) ans+=dis(ch[i],ch[(i+1)%len]); ans+=2*d*acos(-1.0); //等价于圆形周长 cout<<(int)(ans+0.5)<<endl; //四舍五入 return 0; }