poj1113 凸包

题目链接:http://poj.org/problem?id=1113

首先注意的是在c或c++中用强制类型转换将浮点型数据转换为int型的时候是只取整数部分的,要进行四舍五入需要在浮点数据上加0.5来进行,这道题就是让我在这里WA了几次,刚开始也有想到,但是没有改,然后在网上搜测试数据,然后就发现还是这样的错误,也罢,吃一堑长一智!

题目大意是给你一个城堡外围转折点的坐标,让你找到一个长度最短的城墙将城堡围起来,而且围墙离城堡的距离最少有l距离的!

大致思路:采用凸包,找到城堡最外围的点,然后围墙的长度就为所有外围的点的距离和加上接点的距离,因为有最小的距离了,就需要生成点a的两条线求其夹角,然后根据圆的周长公式求得,下面是代码:

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;
#define pi 3.14159265358
typedef struct point
{
	int x,y;
}rr;
point a[1005],*p;
int b[1005];
int n,l;
int Sort(point p1,point p2,point p3,point p4)
{
	int t=(p2.x-p1.x)*(p4.y-p3.y)-(p4.x-p3.x)*(p2.y-p1.y);
	return t;
}
int distance(point p1,point p2,point p3,point p4)
{
	return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)>(p3.x-p4.x)*(p3.x-p4.x)+(p3.y-p4.y)*(p3.y-p4.y)?1:-1;
}
int cmp(const void *a,const void *b)
{
	point *c=(point *)a;
	point *d=(point *)b;
	int temp=Sort(*p,*c,*p,*d);
	if(temp<0)
		return 1;
	else if(temp==0)
		return distance(*p,*c,*p,*d);
	else
		return -1;
}
void foud()//将点集合的所有的外边的点找出来
{
	int i,pc=2;
	b[1]=0;
	b[2]=1;
	b[0]=2;//记录的是总的个数的
	for(i=2; ;)
	{
		i=i%n;///需要将0的也进行一下再结合
		if(i==1)
			break;
		if(b[0]==1)
		{
			b[++pc]=i++;
			b[0]++;
				continue;
		}
        if(Sort(a[b[pc-1]],a[b[pc]],a[b[pc]],a[i])<=0)//删除pc所在的那个店的
		{
			pc--;
			b[0]--;
		}
		else
		{
			b[++pc]=i++;//最后的栈的后面多了一个0是为了下面进行的操作的
			b[0]++;
		}
	}
	n=pc-1;//1到pc的结果的
	b[0]=b[pc-1];//为了循环的
//	for(i=0; i<=n+1; i++)
//		printf("%d\n",b[i]);
}
double dis(point p1,point p2)
{
	double s=(double)((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
	s=sqrt(s);
	return s;
}
double degree(point p1,point p2,point p3,point p4)
{
	double s=(double)((p2.x-p1.x)*(p4.x-p3.x)+(p2.y-p1.y)*(p4.y-p3.y));
	double t=dis(p1,p2)*dis(p3,p4);
	return acos(s/t);//算出来的是角度
}
void len()
{
	double Max=0;
	int i;
	for(i=1; i<=n; i++)
		Max+=sqrt((double)((a[b[i]].x-a[b[i+1]].x)*(a[b[i]].x-a[b[i+1]].x)+(a[b[i]].y-a[b[i+1]].y)*(a[b[i]].y-a[b[i+1]].y)));//求一部分的边长的
	for(i=1; i<=n; i++)
	{
		double m=degree(a[b[i]],a[b[i-1]],a[b[i]],a[b[i+1]]);
		m=pi-m;//对角的
		Max+=l*m;
	}
	printf("%d\n",(int)(Max+0.5));
}
int main()
{
	int i,j,x,y;
    while(scanf("%d%d",&n,&l)!=EOF)
	{
		x=INT_MAX;
		y=INT_MAX;
		for(i=0; i<n; i++)
		{
			scanf("%d%d",&a[i].x,&a[i].y);
			if(a[i].y<y)
			{
				y=a[i].y;j=i;x=a[i].x;
			}
			else if(a[i].y==y && a[i].x<x)
			{
                y=a[i].y;j=i;x=a[i].x;
			}
		}
        a[j].x=a[0].x;a[j].y=a[0].y;
		a[0].x=x;a[0].y=y;
		p=&a[0];
		qsort(&a[1],n-1,sizeof(point),cmp);
//		for(i=0; i<n; i++)
//			printf("%d  %d  %d\n",i,a[i].x,a[i].y);
		foud();
		len();//计算需要的篱笆的长度
	}
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡定的小Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值