TZOJ1417 Wall(凸包模板题 Andrew算法)

题目1471:Wall (tzcoder.cn)

题目大意:在一个坐标系里顺时针给出n个点,找出一个由其中某些点作为顶点组成的凸多边形,恰好能围住所有的N个点,以及还有一个以L为半径圆的周长。

这题用了Andrew算法求凸包。时间复杂度O(nlogn)。

步骤

1.对所有点进行排序,坐标x为主键,坐标y为副键。(第1、n点必在凸包上)

2.顺时针枚举点集,求下凸包(数学概念叉积解决,叉积为负,代表新点在直线右侧,否则在左侧)。用数组模拟栈维护当前在凸包上的点,新点入栈前,需要与栈顶两点比较,若新点在直线右侧或共线,旧点出栈。直到不能弹出,新点进栈。

3.逆序枚举点集,重复2操作。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+10;
const double pi=atan(1.0)*4;//pi的值
int n,l,top;
struct xx
{
    double x,y;
}p[N],s[N];//p为点集,s为栈
bool cmp(xx a,xx b)//排序
{
    if(a.x==b.x)
    {
        return a.y<b.y;
    }
    return a.x<b.x;
}
double cha(xx a,xx b,xx c)//算叉积
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
double jli(xx a,xx b)//算点与点之间的距离
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void andrew()
{
    top=0;
    sort(p+1,p+1+n,cmp);
    for(int i=1;i<=n;i++)//下凸包
    {
        while(top>1&&cha(s[top-1],s[top],p[i])<=0)
        {
            top--;
        }
        s[++top]=p[i];
    }
    int t=top;
    for(int i=n-1;i>=1;i--)//上凸包
    {
        while(top>t&&cha(s[top-1],s[top],p[i])<=0)
        {
            top--;
        }
        s[++top]=p[i];
    }
}
int main()
{
    while(~scanf("%d%d",&n,&l))
    {
        memset(p,0,sizeof(p));
        memset(s,0,sizeof(s));
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        andrew();
        double num=2*pi*l;
        for(int i=1;i<top;i++)
        {
            num+=jli(s[i],s[i+1]);
        }
        printf("%.0f\n",num);
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值