UVA 6859 Points(凸包的应用)

传送门
Peter and Bob are playing a “Points” game on a math sheet of paper. Peter places a few points on the paper — grid nodes. Bob wants to surround them with a polygon so that all marked nodes are lying strictly within (not at the border) the polygon. All sides of the polygon are along the sides or the diagonals of the grid cells and its perimeter is as small as possible. You must determine what is the perimeter of the polygon.
Input
The input file contains several test cases, each of them as described below.
The first line contains integer N — the number of points placed by Peter (1<N<100000) . Each of following N lines contains two integers xi,yi — the point coordinates placed by Peter. The coordinates by absolute value do not exceed 10 6. Some points can match.
Output
For each test case, you need to print one number — the perimeter of the required polygon, on a line by itself. The answer should be printed with accuracy not less than 0.001.
Sample Input
1
0 0

2

1 1

1 2
Sample Output

5.656

7.656854

题目大意:

给定了 N 个点,用一个封闭的折线去把所有的点包起来(不允许在边界上),求最小的周长。

解题思路:

其实我们将每个点周围添加四个点,分别是这个点的上下左右,然后现在一共有 4N 个点,然后求一下凸包,对凸包上的每个点求一下
dx=fabs(st[i].xst[i1].x);
dy=fabs(st[i].yst[i1].y);
sum1+=min(dx,dy);
sum2+=fabs(dxdy);
最会答案就是 2sum1+sum2

My Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const double INF = 1e18+5;
const int MAXN = 1e6 + 5;
const double eps = 1e-10;
const double PI = acos(-1.0);
int double_cmp(double x)
{
    if(fabs(x) < eps)
        return 0;
    if(x > 0)
        return 1;
    return -1;
}

struct Point
{
    double x, y;
    int id;
    Point() {}
    Point (double _x, double _y, int i):x(_x),y(_y),id(i) {}
    bool operator <(const struct Point &tmp)const
    {
        if(double_cmp(x-tmp.x) == 0)
            return double_cmp(y-tmp.y) < 0;
        return double_cmp(x-tmp.x) < 0;
    }
    bool operator == (const struct Point &tmp)const
    {
        return double_cmp(x-tmp.x)==0&&double_cmp(y-tmp.y)==0;
    }
} p[MAXN],st[MAXN];
bool cmp(const Point& p1, const Point& p2)
{
    return atan2(p1.y, p1.x) < atan2(p2.y, p2.x);
}
double XMulti(Point a, Point b, Point c)///ac X ab
{
    return (c.x-a.x)*(b.y-a.y) - (b.x-a.x)*(c.y-a.y);
}

double dis(Point a, Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
double dis2(Point a, Point b)
{
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
double dot(Point a, Point b, Point c)///点积 ab . ac
{
    double s1 = b.x-a.x;
    double t1 = b.y-a.y;
    double s2 = c.x-a.x;
    double t2 = c.y-a.y;
    return s1*s2 + t1*t2;
}

int ConvexHull(Point *p, int n, Point *st)///凸包
{
    sort(p, p+n);
    n = unique(p, p+n)-p;///去重
    int m = 0;
    for(int i=0; i<n; i++)
    {
        while(m>1 && XMulti(st[m-2],p[i],st[m-1])<=0)
            m--;
        st[m++] = p[i];
    }
    int k = m;
    for(int i=n-2; i>=0; i--)
    {
        while(m>k && XMulti(st[m-2],p[i],st[m-1])<=0)
            m--;
        st[m++] = p[i];
    }
    if(n > 1)
        m--;
    return m;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int sum = 0;
        for(int i=0; i<n; i++)
        {
            double xx, yy;
            scanf("%lf%lf",&xx,&yy);
            p[sum].x = xx+1, p[sum++].y = yy;
            p[sum].x = xx-1, p[sum++].y = yy;
            p[sum].x = xx, p[sum++].y = yy+1;
            p[sum].x = xx, p[sum++].y = yy-1;
        }
        int cnt = ConvexHull(p, sum, st);
        double sum1 = 0, sum2 = 0;
        double dx, dy;
        dx = fabs(st[0].x-st[cnt-1].x);
        dy = fabs(st[0].y-st[cnt-1].y);
        sum1 += min(dx, dy);
        sum2 += fabs(dx-dy);
        for(int i=1; i<cnt; i++){
            dx = fabs(st[i].x-st[i-1].x);
            dy = fabs(st[i].y-st[i-1].y);
            sum1 += min(dx, dy);
            sum2 += fabs(dx-dy);
        }
        ///cout<<sum1<<" "<<sum2<<endl;
        double ans = sum1*sqrt(2.0)+sum2;
        printf("%.6lf\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值