poj1113(凸包)

/*
translation:
	用一条线把若干个点包起来,并且线距离任何一个点的距离都不小于r。求这条线的最小距离是多少?
solution:
	直接求凸包,然后凸包的周长加上一个圆的周长即可。
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>

using namespace std;
const int maxn = 50000 + 5;
const double EPS = 1e-10;
const double pi = 3.14159265;

double add(double a, double b)
{
    if(abs(a + b) < EPS * (abs(a) + abs(b)))    return 0;
    return a + b;
}

struct P
{
    double x, y;
    int id;
    P(){}
    P(double x_, double y_):x(x_),y(y_){}

    bool operator < (const P& rhs) const {
        return x < rhs.x || (x == rhs.x && y < rhs.y);
    }

    P operator + (P p) {
        return P(add(x, p.x), add(y, p.y));
    }
    P operator - (P p) {
        return P(add(x, -p.x), add(y, -p.y));
    }
    P operator * (double d) {
        return P(x * d, y * d);
    }
    double dot(P p) {    //内积
        return add(x * p.x, y * p.y);
    }
    double det(P p) {   //外积
        return add(x * p.y, -y * p.x);
    }
} ps[maxn];
int n, r;

double dist(P p, P q)
{
    double ans = (p - q).dot(p - q);
    return sqrt(ans);
}

bool cmp_id(const P& lhs, const P& rhs)
{
    return lhs.id < rhs.id;
}

double graham()
{
    sort(ps, ps + n);
    int k = 0;
    vector<P> res;
    res.resize(n * 2);

    for(int i = 0; i < n; i++) {
        while(k > 1 && (res[k-1] - res[k-2]).det(ps[i] - res[k-1]) <= 0)    k--;
        res[k++] = ps[i];
    }

    for(int i = n - 2, t = k; i >= 0; i--) {
        while(k > t && (res[k-1] - res[k-2]).det(ps[i] - res[k-1]) <= 0)    k--;
        res[k++] = ps[i];
    }
    res.resize(k - 1);

    double len = 0;
    sort(res.begin(), res.end(), cmp_id);
    for(int i = 0; i < res.size()-1; i++)
        len += dist(res[i], res[i+1]);

    int s = res.size();
    len += dist(res[0], res[s-1]);
    return len;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(~scanf("%d%d", &n, &r)) {
        for(int i = 0; i < n; i++) {
            cin >> ps[i].x >> ps[i].y;
            ps[i].id = i;
        }

        double tmp = graham() + 2.0 * pi * r;
        int ans = tmp + 0.5;
        cout << ans << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值