凸包模板

/*
凸包:
1.选取最左下边的点p0
2.根据剩余的m点集Q相对p0的极角排序,如果极角相同,只考虑最远的点
3.对堆栈进行初始化
	push(p0,S)
	push(p1,S)
	push(p2,S)
	for i=3 to m 
		do the angle formed by points next_to_top(s) top(s) and pi make a 
		nonleft turn
			do pop(S)
	    PUSH(pi,S)
	return S
*/ 

/*
struct point
{  double x,y;
};
bool mult(point p0,point p1,point p2)
{   return (p1.x-p0.x)*(p2.y-p0.y)>=(p2.x-p0.x)*(p1.y-p0.y);
}
bool operator<(const point &p1,const point &p2)
{  return p1.y<p2.y||(p1.y==p2.y&&p1.x<p2.x);
}
int graham(point pnt[],int n,point res[])//pnt是图中的所有的点,res是通过判断后在凸边行边上的点,
//而且这些点都是按逆时针存储的,n是所有点的个数。
{  int i,len,k=0,top=1;
   sort(pnt, pnt + n);
   if(n==0) return 0; res[0]=pnt[0];
   if(n==1) return 1; res[1]=pnt[1];
   if(n==2) return 2; res[2]=pnt[2];
   for(i=2;i<n;i++)
   {  while(top&&mult(pnt[i],res[top],res[top-1]))
        top--;
      res[++top]=pnt[i];
   }
   len=top;res[++top]=pnt[n-2];
   for(i=n-3;i>=0;i--)
   {  while(top!=len&&mult(pnt[i],res[top],res[top-1]))
        top--;
      res[++top]=pnt[i];
   }
   return top; // 返回凸包中点的个数
}


例题1:nyist 圈水池(求凸包中的每个顶点-凸包的简单应用)
描述
       有一个牧场,牧场上有很多个供水装置,现在牧场的主人想要用篱笆把这些供水装置圈起来,以防止不是自己的牲畜来喝水,各个水池都标有各自的坐标,现在要你写一个程序利用最短的篱笆将这些供水装置圈起来!(篱笆足够多,并且长度可变)
输入 
      第一行输入的是N,代表用N组测试数据(1<=N<=10),第二行输入的是m,代表本组测试数据共有m个供水装置(3<=m<=100)接下来m行代表的是各个供水装置的横纵坐标
输出 
     输出各个篱笆经过各个供水装置的坐标点,并且按照x轴坐标值从小到大输出,如果x轴坐标值相同,再安照y轴坐标值从小到大输出
样例输入
1
4
0 0
1 1
2 3
3 0
样例输出
0 0
2 3
3 0
code:
*/


#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const double EPS = 1E-6;

struct point
{   
	int x,y;
};
point p[105],res[105];
double Dist(const point &arg1, const point &arg2)
{
 	return sqrt( (arg1.x - arg2.x)*(arg1.x - arg2.x) + (arg1.y - arg2.y)*(arg1.y - arg2.y) );
}
bool multi(point p0,point p1,point p2)
{   
	return (p1.x-p0.x)*(p2.y-p0.y)>(p2.x-p0.x)*(p1.y-p0.y);
}
int mysort1(point a,point b)
{   if(a.y!=b.y) return a.y<b.y;
    if(a.y==b.y&&a.x!=b.x) return a.x<b.x;
}
bool cmp(const point &a,const point &b)
{
	point temp=p[0];
	double xmt=(a.x-temp.x)*(b.y-temp.y)-(b.x-temp.x)*(a.y-temp.y);
	if(xmt)                             //向量不共线就按逆时针旋转
		return xmt>0;
	return Dist(a,temp)>Dist(b,temp);//向量共线取最长的。
}

int main()
{   int n,k,len;
    cin>>k;
    
    while(k--)
    { 
	  cin>>n;
      for(int i=0;i<n;i++)
         cin>>p[i].x>>p[i].y;
      sort(p,p+n,mysort1);//排序,找到最左下角的点 
	   
      res[0]=p[0];

      sort(p+1,p+n,cmp);//按照极角排序 
      res[1]=p[1];
      res[2]=p[2];
      int top=2;
      for(int i=3;i<n;i++)
      {  
			while(multi(p[i],res[top],res[top-1])) 
				top--;
			res[++top]=p[i];
      } 
      
	  for(int i=0;i<=top;i++)
         cout<<res[i].x<<" "<<res[i].y<<endl;
    } 
    
    system("pause");
    return 0;
}

 

posted @ 2012-05-28 21:11  张兰云  阅读(371)  评论(0编辑  收藏  举报