计算几何--凸包(C++)

目录

圈奶牛

题目描述

输入格式

输出格式

输入输出样例

输入 

输出 

说明/提示

数据规模与约定

代码展示:

Graham版

Andrew版


圈奶牛

题目描述

农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。

输入格式

输入数据的第一行是一个整数。表示农夫约翰想要围住的放牧点的数目 n。

第 2 到第 (n+1) 行,每行两个实数,第 (i+1) 行的实数 xi​,yi​ 分别代表第 i 个放牧点的横纵坐标。

输出格式

输出输出一行一个四舍五入保留两位小数的实数,代表围栏的长度。

输入输出样例

输入 
4
4 8
4 12
5 9.3
7 8
输出 
12.00

说明/提示

数据规模与约定

对于 100% 的数据,保证 1≤n≤10^5,−10^6≤xi​,yi​≤10^6。小数点后最多有 2 位数字。

代码展示:

Graham版
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
struct Node{
	double x,y;
}p[N],stk[N];
double dis(Node a,Node b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp(Node a,Node b)
{
	double x0=p[1].x,y0=p[1].y;
	double det=(a.x-x0)*(b.y-y0)-(a.y-y0)*(b.x-x0);
	if(det!=0)
	return det>0;
	return dis(a,p[1])<dis(b,p[1]);
}
double cross(Node a,Node b,Node c)
{
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>p[i].x>>p[i].y;
	int idx=1;
	for(int i=1;i<=n;i++)
	{
		if(p[i].y<p[idx].y)
		idx=i;
		else if(p[i].y==p[idx].y&&p[i].x<p[idx].x)
		idx=i;
	}
	swap(p[idx],p[1]);
	sort(p+2,p+n+1,cmp);
	p[n+1]=p[1];
	int top=0;
	for(int i=1;i<=n+1;i++)
	{
		while(top>1&&cross(stk[top-1],stk[top],p[i])<0)
		top--;
		stk[++top]=p[i];
	}
	double res=0;
	for(int i=1;i<top;i++)
	res+=dis(stk[i],stk[i+1]);
	cout<<fixed<<setprecision(2)<<res;
	return 0;
}
Andrew版
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
struct Node{
	double x,y;
}p[N],stk[N];
double dis(Node a,Node b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp(Node a,Node b)
{
	return a.x!=b.x? a.x<b.x : a.y<b.y;
}
double cross(Node a,Node b,Node c)
{
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>p[i].x>>p[i].y;
	sort(p+1,p+n+1,cmp);
	int top=0;
	for(int i=1;i<=n;i++)
	{
		while(top>1&&cross(stk[top-1],stk[top],p[i])<=0)
		top--;
		stk[++top]=p[i];
	}
	int t=top;
	for(int i=n-1;i>=1;i--)
	{
		while(top>t&&cross(stk[top-1],stk[top],p[i])<=0)
		top--;
		stk[++top]=p[i];
	}
	double res=0;
	for(int i=1;i<top;i++)
	res+=dis(stk[i],stk[i+1]);
	cout<<fixed<<setprecision(2)<<res;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值