凸包算法的初步学习

所谓凸包问题是指给定一系列的点,求解出这些点中组合起来的能把所有其他点包裹起来的最小多边形。

预备知识是向量的点乘和方向判定。

方法是,首先找出纵坐标最小的点,若有相同最小纵坐标再取横坐标最小,如果有相同的点可以删掉一个;之后以选定的点为基准,按照每点与基准点的角度大小进行扫描,扫描规

 

以上图为例,首先以A为基准点,首先插入B,可知B一定在凸包上,接下来扫描C...当扫描到G时,向量<C,H>,和向量<H,G>的点乘为正(逆时针扫描时判断是否为负,顺时针相反),则删掉H,回溯删掉所有符号不相同的点。扫描完一遍后,即可得到凸包。

其算法空间复杂度为O(1)。代码如下:

#include<stdio.h> 
#include<math.h> 
#include<algorithm> 
using namespace std;  
struct Point 
{  
double x,y,len;  
}Pt[20000],Stack[20000],Point_A; 
double Cross(Point a,Point b,Point c) 
{  return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); }  
double Dis(Point a,Point b) 
{  return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2)); }  
void FindPoint(int n) 
{  
int i,tempNumber=0; 
Point tempPoint; 
Point_A=Pt[0]; 
for(i=1;i<n;i++) 
{  
if(Pt[i].y<Point_A.y||Pt[i].y==Point_A.y&&Pt[i].x<Point_A.x) 
{ tempNumber=i; 
Point_A=Pt[i]; 
} 
}  
tempPoint=Pt[0];  
Pt[0]=Pt[tempNumber];  
Pt[tempNumber]=tempPoint; }  
bool Cmp(Point a,Point b) 
{  
double k=Cross(Point_A,a,b); 
if(k>0) return true; 
if(k<0) return false; 
a.len=Dis(Point_A,a); 
b.len=Dis(Point_A,b); 
return a.len>b.len; 
}  
void Graham(int n) 
{  
int i,top=2; 
Pt[n]=Pt[0]; 
Stack[0]=Pt[0]; 
Stack[1]=Pt[1];  
Stack[2]=Pt[2]; 
for(i=3;i<=n;i++) 
{   
while(Cross(Stack[top-1],Stack[top],Pt[i])<=0&&top>1) top--; 
Stack[++top]=Pt[i]; 
} 
}  
int main(void) 
{  
int i,Num;  
while(scanf("%d",&Num)!=EOF) 
{  
for(i=0;i<Num;i++) scanf("%lf%lf",&Pt[i].x,&Pt[i].y); 
FindPoint(Num);  
sort(Pt,Pt+Num,Cmp); 
Graham(Num); 
}  
return 0; 
} 

  

posted on 2013-11-06 20:20  金仁赫  阅读(291)  评论(0)    收藏  举报

导航