poj 1113 凸包问题

我的第一道凸包题,终于弄懂了Graham算法,对我来说弄懂一个算法是一个痛苦的过程,我痛苦了我好几天……

Grahma算法模板:

1、  寻找一个基准点,这个点通常是最左边的最下面那个点(其实只要这个点一定会在凸包边界上就行),然后将之个点置于第一个位置。

2、  将所有点按相对于基准点的极角排序。

3、  因为排序之后前两个点一定会在凸包上,假设第三个点也在凸包上,因此我们可以从第四个点开始依次扫描每个点。对于每个当前点他在当前时刻是极角最大的点,所以在当前时刻它必定在凸包上,那么此时就可能改变了它前一个点是不是在凸包上。怎么判断呢?我们可以咱当前点到推三个点,假设是p1,p2,p3,判断这三个点所形成的角是不是大于180度,小于180度继续扫描下一个点,若大于180度说明第二个点一定在凸包内部,然后我们暂时停止扫描下一个点,将p1,p2各自后退一个点继续判断p1,p2,p3所组成的角是不是大于180度,(这也就是所谓的“退化”问题,看了《算法导论》后才知道这儿需要有个循环)若仍然大于180度循环这种操作直到三个点组成的角小于等于180度,最后继续扫描下一个点,直到结束。在这个过程中我们可以用栈来保存凸包边上的点。

该题需要最后算出各边长的和再加上圆的周长。

#include<iostream>

#include<cmath>

using namespace std;

#define MAX_INT 123456789

struct point

{

	int x,y;

};

point vertex[1001],stack[1000];

int angle(point p1,point p2,point p0)//判断极角大小

{	

	return (p1.y-p0.y)*(p2.x-p0.x)-(p2.y-p0.y)*(p1.x-p0.x);

}

int dist(point p1,point p2)

{

	return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);

}

int cmp(const void* pp,const void* qq)//排序判断条件

{

	point p1,p2;

	p1=*(point*) pp; p2=*(point*) qq;

	if(angle(p1,p2,vertex[0])>0)

		return 1;

	else if(angle(p1,p2,vertex[0])==0 && dist(p1,vertex[0])>dist(p2,vertex[0]))

		return 1;

	return -1;

}

int judge(point p1,point p2,point p3)//判断三点组成的角度

{

	return (p3.y-p2.y)*(p2.x-p1.x)-(p2.y-p1.y)*(p3.x-p2.x);

}

double Graham(int n,int m)

{

	int sum_max=0,i=0;  

	point p1,p2;

	double sum=0;

	p1=vertex[1],p2=vertex[2];

	stack[0]=vertex[0];

	stack[1]=vertex[1];

	stack[2]=vertex[2];

	sum_max=2;

	for(i=3;i<n;i++)

	{

		while(1)//解决退化问题

		{

			if(judge(p1,p2,vertex[i])>=0)

			{

				p1=p2,p2=vertex[i];   

				stack[++sum_max]=vertex[i];

				break;

			}

			else

			{

				--sum_max;

				p2=stack[sum_max];

				p1=stack[sum_max-1];

			}

		}

	}

	for(i=0;i<sum_max;i++)

		sum+=sqrt((double)dist(stack[i],stack[i+1]));

	sum+=sqrt((double)dist(stack[sum_max],vertex[0]))+3.1415926*2*m;

	return sum;

}

int main()

{

	int i,m,n,min;

	point minPoint;

	while(scanf("%d%d",&n,&m)!=EOF)

	{

		memset(vertex,0,sizeof(vertex));

		minPoint.x=minPoint.y=MAX_INT;

		for(min=i=0;i<n;i++)

		{

			scanf("%d%d",&vertex[i].x,&vertex[i].y);

			if(minPoint.x>vertex[i].x) 

			{

				minPoint=vertex[i];

                min=i;

			}

			else if(minPoint.x==vertex[i].x && minPoint.y>vertex[i].y)

			{

				minPoint=vertex[i];

				min=i;

			}

		}

        vertex[min]=vertex[0]; vertex[0]=minPoint;

		qsort(vertex+1,n-1,sizeof(vertex[0]),cmp);



		printf("%.lf\n",Graham(n,m));

	}

	return 0;

}

 

你可能感兴趣的:(poj)