现在的位置: 首页 > 综合 > 正文

POJ 3608 Bridge Across Islands(模板小汇)

2019年02月11日 ⁄ 综合 ⁄ 共 4040字 ⁄ 字号 评论关闭

求两个凸包间的最短距离。

大部分都是抄的小岛前辈的模板。

真是无私奉献的典范啊!应有尽有,巨细靡遗。。

顺便连带整理了一下自己的。(感觉自己的模板也写得变紧凑了。。)

#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 10010
#define eps 1e-10

//const double pi = acos(-1.0);
inline double sig(double x) { return (x > eps) - (x < -eps); };
template <class T> inline T sqr(T a) { return a * a; }

struct Point
{
    double x, y;
    Point() {}
    Point(double _x, double _y): x(_x), y(_y) {}
    void in();
    void out() const;
    double len() const;
    double len2() const;
    double dis(const Point &argu) const;
    double dis2(const Point &argu) const;
    bool operator <(const Point &argu) const;
    Point operator -(const Point &argu) const;
    double operator ^(const Point &argu) const;
    double operator *(const Point &argu) const;
};

struct Segment
{
    Point a, b;
    Segment() {}
    Segment(Point _a, Point _b): a(_a), b(_b) {}
    void in();
    Point d() const;
    void out() const;
    double len() const;
    double len2() const;
    int sgn(const Segment &argu) const;
    bool qrt(const Segment &argu) const;
    double dis2(const Point &argu) const;
    double dis2(const Segment &argu) const;
};

struct Line
{
    Segment l;
    Line() {}
    Line(Segment _l): l(_l) {}
    double dis2(const Point &argu) const;
    double dis2(const Segment &argu) const;
};
inline double Cross(const Point &o, const Point &a, const Point &b) { return (a - o) ^ (b - o); }

void Point::in() { scanf("%lf%lf", &x, &y); }
double Point::len() const { return sqrt(len2()); }
double Point::len2() const { return x * x + y * y; }
void Point::out() const{ printf("%.0lf %.0lf\n", x, y); }
double Point::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Point::operator ^(const Point &argu) const { return x * argu.y - y * argu.x; }
double Point::operator *(const Point &argu) const { return x * argu.x + y * argu.y; }
Point Point::operator -(const Point &argu) const { return Point(x - argu.x, y - argu.y); }
bool Point::operator <(const Point &argu) const { return sig(x - argu.x) == 0 ? y < argu.y : x < argu.x; }
double Point::dis2(const Point &argu) const { return (x - argu.x) * (x - argu.x) + (y - argu.y) * (y - argu.y); }

void Segment::in() { a.in(), b.in(); }
Point Segment::d() const { return b - a; }
double Segment::len2() const { return d().len2(); }
double Segment::len() const { return sqrt(len2()); }
void Segment::out() const { a.out(), b.out(); }
double Segment::dis2(const Segment &argu) const
{
    if(~sgn(argu)) return 0;
    return min(min(dis2(argu.a), dis2(argu.b)), min(argu.dis2(a), argu.dis2(b)));
}
double Segment::dis2(const Point &argu) const
{
    Point pa = argu - a, pb = argu - b;
    if(sig(d() * pa) <= 0) return pa.len2(); if(sig(d() * pb) >= 0) return pb.len2();
    Line l = Line((*this)); return l.dis2(argu);
}
int Segment::sgn(const Segment &argu) const
{
    if(!qrt(argu)) return -1;
    return sig(Cross(a, b, argu.a)) * sig(Cross(a, b, argu.b)) <= 0 &&
           sig(Cross(argu.a, argu.b, a)) * sig(Cross(argu.a, argu.b, b)) <= 0 ? 1 : -1;
}
//快速排斥实验
bool Segment::qrt(const Segment &argu) const
{
    return min(a.x, b.x) <= max(argu.a.x, argu.b.x) && min(a.y, b.y) <= max(argu.a.y, argu.b.y) &&
           min(argu.a.x, argu.b.x) <= max(a.x, b.x) && min(argu.a.y, argu.b.y) <= max(a.y, b.y);
}

double Line::dis2(const Point &argu) const { return sqr(fabs(l.d() ^ (argu - l.a))) / l.len2(); }
double Line::dis2(const Segment &argu) const
{
    Point v1 = argu.a - l.a, v2 = argu.b - l.b; double d1 = l.d() ^ v1, d2 = l.d() ^ v2;
    return sig(d1) != sig(d2) ? 0 : sqr(min(fabs(d1), fabs(d2))) / l.len2();
}

int ConvexHull(Point p[], Point ch[], int n)
{
    sort(p, p + n);
    int top = 0;
    for(int i = 0; i < n; i++)
    {
        while(top > 1 && Cross(ch[top - 2], ch[top - 1], p[i]) <= 0) top--;
        ch[top++] = p[i];
    }
    int t = top;
    for(int i = n - 2; i >= 0; i--)
    {
        while(top > t && Cross(ch[top - 2], ch[top - 1], p[i]) <= 0) top--;
        ch[top++] = p[i];
    }
    top--;
    return top;
}

double RotatingCalipers(Point p1[], int n1, Point p2[], int n2)
{
    double ret = 1e15;
    int t = 0, t1 = 1, t2 = 1;
    for(int i = 0; i < n1; i++) if(p1[i].y > p1[t1].y) t1 = i;
    for(int i = 0; i < n2; i++) if(p2[i].y < p2[t1].y) t1 = i;
    for(int i = 0; i < n1; i++)
    {
        while(sig((p1[t1 + 1] - p1[t1]) ^ (p2[t2 + 1] - p2[t2])) > 0) t2 = (t2 + 1) % n2;
        Segment s1 = Segment(p1[t1], p1[t1 + 1]);
        Segment s2 = Segment(p2[t2], p2[t2 + 1]);
        ret = min(ret, s1.dis2(s2));
        t1 = (t1 + 1) % n1;
    }
    return ret;
}

Point p1[MAXN], ch1[MAXN];
Point p2[MAXN], ch2[MAXN];
int n1, n2, c1, c2;

void solve()
{
    c1 = ConvexHull(p1, ch1, n1); ch1[c1] = ch1[0];
    c2 = ConvexHull(p2, ch2, n2); ch2[c2] = ch2[0];
    double d1 = RotatingCalipers(ch1, c1, ch2, c2);
    double d2 = RotatingCalipers(ch2, c2, ch1, c1);
    printf("%.5lf\n", sqrt(min(d1, d2)));
}

int main()
{
//    freopen("3608.in", "r", stdin);

    while(scanf("%d%d", &n1, &n2) && (n1 || n2))
    {
        for(int i = 0; i < n1; i++) p1[i].in();
        for(int i = 0; i < n2; i++) p2[i].in();
        solve();
    }
    return 0;
}

抱歉!评论已关闭.