您的位置:首页 > 大数据 > 人工智能

[caioj]1214:【计算几何】凸包 graham scan求凸包

2017-08-04 14:07 274 查看
【题意】 

在一个平面坐标系上有n个点,用笔画一个多边形,使得多边形包含这n个点(点在多边形的边上也算包含)。 

求多边形的最小周长。


题解:

显然是要求包含这n个点的最小凸包。我们可以使用Graham Scan来求凸包,时间复杂度为nlog(n)
。大概流程:先选择一个y最小的点,若有多个则选择x最小的,接着按扫描顺序对点进行排序,然后建立一个栈,栈中开始只有1、2号点。对于每个新加入的点a[i],以sta[top-1]为基准点,看sta[top]到a[i]的旋转方向是否为顺时针,若是,则将栈顶元素出栈,因为并不能构成凸包。重复此流程,最后算出栈中剩下的点的两点距离之和即可

。code:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{double x,y;}a[1010];
double multi(node p1,node p2,node p0)
{
double x1,y1,x2,y2;
x1=p1.x-p0.x;
y1=p1.y-p0.y;
x2=p2.x-p0.x;
y2=p2.y-p0.y;
return x1*y2-x2*y1;
}
double dis(node p1,node p2)
{
double x1=p1.x,y1=p1.y,x2=p2.x,y2=p2.y;
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int n,top=2;
node sta[1010];
bool cmp(node p1,node p2)
{
double t=multi(p1,p2,a[1]);
if(t<0)return false;//need swap
if(t==0&&dis(a[1],p1)>dis(a[1],p2))return false;
return true;//not swap
}
void graham()
{
sort(a+2,a+n+1,cmp);
sta[1]=a[1];sta[2]=a[2];
for(int i=3;i<=n;i++)
{
while(top>1&&multi(sta[top],a[i],sta[top-1])<=0)top--;
sta[++top]=a[i];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&a[i].x,&a[i].y);
if(a[i].y<a[1].y||(a[i].y==a[1].y&&a[i].x<a[1].x))
swap(a[1],a[i]);
}
graham();
double ans=0.0;
for(int i=2;i<=top;i++)ans+=dis(sta[i],sta[i-1]);
printf("%.4lf",ans+dis(sta[1],sta[top]));
10d74

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: