关于凸包:grahman scan

二维凸包问题(其实还有三维的,但是这里不做研究)是一类关于一个平面上有n个点,让你连接最少的点使给出的所有点在被划定的区域里。如图1: Figure1,这就是一个最优的解。
下面我们开始介绍求解方法之一:graham   scan、。
          首先我们得知道两个有相同起点的矢量(假设p1-->p2,     p1-->p3)的叉积的正负(叉积公式:(p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))可以代表矢量一是在矢量二的顺时针或逆时针方向。那么根据这个性质,我们可以先从上图取三个点:BG E   B-->G,E-->G调整成B-->G时我们只需要判断一下这两个矢量:B-->E    E-->G的叉积就行了
          理解了这些我们就可以开始接下来的讨论了我们可以对于每一个顶点进行比较,然后得出结论。当然我们可以确定处在最左下的点一定会被取到。那我们把这个当作起点,一个点一个点向外扩张。当然扩张前我们需要对其他点对于以起点为原点x轴的角度先排序,这样就可以保证每一次我们取得点是有序的。
        代码如下:

    #include
#include 
using namespace std;

struct p {
  int x,y;
};
p point [1001];
int n;
p beginn;

int rnd(p beginn,p x,p y)
  {
  return(x.x-beginn.x)*(y.y-beginn.y)-(y.x-beginn.x)*(x.y-beginn.y);
  }

void kp(int x,int y)
{
int i,j;
p k,l;
i=x;j=y;k=point[(x+y)/2];
while(i<=j)
  {
  while(rnd(beginn,point[i],k)<0)i++;
  while(rnd(beginn,point[j],k)>0)j--;
  if(i<=j)
  {
  l=point[i];point[i]=point[j];point[j]=l;
  i++;j--;
  }
 
  }
if(i
  if(j>x)kp(x,j);
}

p line[10001];
int main()
{
int i,j=1,k;
scanf("%d",&n);
for(i=1;i<=n;i++)
  {
  scanf("%d%d",&point[i].x,&point[i].y);
      if(point[j].x>point[i].x||(point[j].x==point[i].x&&point[j].y>point[i].y))
              j=i;
  }
  beginn=point[j];
  point[j]=point[n];
  kp(1,--n);
 
 
  line[1]=beginn;
  line[2]=point[1];
  line[3]=point[2];
  int tail=3;
  for(i=3;i<=n;i++) 
          {
          if(tail<3)
            line[++tail]=point[i];
          else  
            {
              while(rnd(line[tail-1],line[tail],point[i])>=0&&tail!=0)
                tail--;
              line[++tail]=point[i];
                   
}
}
 
printf("%d\n",tail);
for(i=1;i<=tail;i++)
  printf("%d:%d%d\n",i,line[i].x,line[i].y);
}


由于本人只用了几个数据来验证代码正确性,所以代码可能有点问题,欢迎各路大神来指点

你可能感兴趣的:(关于凸包:grahman scan)