UVALive 6859--凸包

本文介绍了一种算法,用于解决给定点集时构造包含所有点且周长最小的多边形问题。多边形的边必须为水平、垂直或45度斜线,并确保所有点位于多边形内部。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

在一个直角坐标系内给n个点的坐标 ,要求画一个多边形,

条件:

1、将所有的点都要包含进去(保障所有的点在多边形的内部,不在多边形的边上);

2、保证多边形的顶点坐标是整数;

3、多边形顶点之间的连线要么是一条水平竖直的直线,要么是一条45度的斜线;

保证以上三种条件的情况下,保证多边形的周长最小,输出多边形的周长。


输入:

1

0 0


2

1 1

1 2


输出:

5.656

7.656854


分析:

当一个点的时候,最小的多边形是将该点周围的四个点连起来组成的多边形,这样是最小的。根据这种情况,将所有的点周围的点

都找出来,之后去重之后求凸包。

x=abs(res[i-1].x-res[i].x);

y=abs(res[i-1].y-res[i].y);

len+=abs(x-y)+min(x,y)*sqrt(2).


代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <cmath>
using namespace std;

typedef long long ll;
const int maxn=500005;

struct node
{
    int x,y;
    node(int a=0,int b=0):x(a),y(b){}
    bool operator <(const node &r) const
    {
        return (x==r.x?y<r.y:x<r.x);
    }
    node operator -(node r)const
    {
        return node(x-r.x,y-r.y);
    }
} m[maxn];
node res[maxn];
int n,top;
set <node> s;

int solve()
{
    sort(m,m+n);
    int num=0;
    for(int i=0; i<n; i++)
    {
        while(num>1&&(1ll*(res[num-1]-res[num-2]).x*(m[i]-res[num-2]).y-1ll*(res[num-1]-res[num-2]).y*(m[i]-res[num-2]).x)<=0)
            num--;
        res[num++]=m[i];
    }
    int k=num;
    for(int i=n-2; i>=0; i--)
    {
        while(num>k&&(1ll*(res[num-1]-res[num-2]).x*(m[i]-res[num-2]).y-1ll*(res[num-1]-res[num-2]).y*(m[i]-res[num-2]).x)<=0)
            num--;
        res[num++]=m[i];
    }
    if(n>1)
        num--;
    return num;
}
int main()
{
    int t,x,y,px,py,pos,tmp,ans;
    node kk;
    double len=0;
    set<node>::iterator si;
    while(scanf("%d",&t)!=EOF)
    {
        py=-1;
        s.clear();
        len=0.0;
        ans=0;
        for(int i=0; i<t; i++)
        {
            scanf("%d%d",&x,&y);
            kk.x=x-1;
            kk.y=y;
            s.insert(kk);
            kk.x=x+1;
            kk.y=y;
            s.insert(kk);
            kk.x=x;
            kk.y=y+1;
            s.insert(kk);
            kk.x=x;
            kk.y=y-1;
            s.insert(kk);
        }
        n=s.size();
        si=s.begin();
        for(int i=0; i<n; i++)
        {
            m[i]=*si;
            si++;
        }
        int tt=solve();
        res[tt].x=res[0].x;
        res[tt++].y=res[0].y;
        for(int i=1; i<tt; i++)
        {
            x=abs(res[i-1].x-res[i].x);
            y=abs(res[i-1].y-res[i].y);
            len+=abs(x-y)+min(x,y)*sqrt(2);
        }
        printf("%.10lf\n",len);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值