POJ 1113

凸包问题,但是可能有人对为什么最后的答案是凸包周长加一个圆的周长有疑问,参考图片,角a1与a2互补,因为另外两个角均为90度,n边形的内角和为(n-2)*180,这样的话,由于a2=180-a1,对于所有的a2的和为(n-2)*180,也可以写成n*180-a1总(因为会有n个类似a2的角,所以是n*180),a1总就是所有的a1的和,这样的话正好就是一个完整的圆,适用于所有的情况,网上很多解释冗长,不是非常好理解

代码如下:

#include<stdio.h>
#include<algorithm> 
#include<math.h>
#define pi 3.1415926
using namespace std;
int n;
struct point
{
	double x,y;
}p1[1000],p2[1000];
double xmult(point a,point b,point c)
{
	return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
double dis(point a,point b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int cmp(point a,point b)
{
	double ans;
	ans=xmult(a,b,p1[0]);
	if(ans>0)
	{
		return 1;
	}
	else if(ans==0&&dis(a,p1[0])<dis(b,p1[0]))//共线情况,只选取断端点 
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
int stapoint()
{
	int i,k=0;
	for(i=0;i<n;i++)
	{
		if(p1[i].y<=p1[k].y)
		{
			if(p1[i].y<p1[k].y)
			{
				k=i;
			}
			else
			{
				if(p1[i].x<p1[k].x)
				{
					k=i;
				}
			}
		}
	}
	return k;
}
int Graham() 
{
	int i,sta,top;
	point p3;
	top=2;
	if(n<=3)
	{
		for(i=0;i<3;i++)
		{
			p2[i]=p1[i];
		}
		return n;
	}
	sta=stapoint();
	p3=p1[0];
	p1[0]=p1[sta];
	p1[sta]=p3;
	sort(p1+1,p1+n,cmp);
	p2[0]=p1[0];
	p2[1]=p1[1];
	p2[2]=p1[2];
	for(i=3;i<n;i++)
 	{
		while(xmult(p1[i],p2[top],p2[top-1])>=0)
   		{
   			top--;
   		}
  		p2[++top]=p1[i];
 	}
 	return ++top;
}
int main()
{
	int i,l,num;
	double len=0;
	scanf("%d %d",&n,&l);
	for(i=0;i<n;i++)
	{
		scanf("%lf %lf",&p1[i].x,&p1[i].y);
	}
	num=Graham();
	for(i=0;i<num-1;i++)
	{
		len+=dis(p2[i],p2[i+1]);
	}
	len+=dis(p2[0],p2[num-1]);
	len+=2*pi*l;
	if(len-(int)len>=0.5)
	{
		printf("%d\n",(int)len+1);
	}
	else
	{
		printf("%d\n",(int)len);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值