Skip to content

计算几何

bool PointInPolygon(Point p, const Polygon & poly) {
    int n = poly.size();
    if (n < 3) return false;
    sort(poly.begin(), poly.end());
    Point b = poly[0], c = poly[1], a = poly[n - 1];
    bool clcws = ((b - a) ^ (c - b)) < 0;
    bool flag1 = true, flag2 = true;
    for (int i = 0; i < n; i++) {
        Line l(poly[i], poly[(i + 1) % n]);
        if (PointInSeg(p, l)) return true;
        int side = SideOfLine(p, l);
        if (clcws && side > 0) flag1 = false;
        if (!clcws && side < 0) flag2 = false;
        if (!flag1 && !flag2) return false;
    }
    return true;
}


Point LineCrossLine(Line l, Line m) {
    Point a = l.b - l.a, b = m.b - m.a, s = m.a - l.a;
    return l.a + a * ((b^s) / (b^a));
}

pair<int, Point> LineCrossSeg(Line l, Line seg) {
    int a = SideOfLine(seg.a, l);
    int b = SideOfLine(seg.b, l);
    if (a*b <= 0) return make_pair(1, LineCrossLine(l, seg));
    else return make_pair(0, Point(0, 0));
}

// polar angle order comparator
struct comp {
    Point p0;
    comp(const Point& p) :p0(p) {}
    bool operator ()(const Point& p1, const Point& p2) const {
        int s = epssgn((p1 - p0) ^ (p2 - p0));
        if (s == 0) return dist(p0, p1) < dist(p0, p2);
        else return s > 0;
    }
};

// polar angle order
int graham(vector<Point>& ps, vector<Point>& stk) {
    if (ps.size() < 3) return 0;
    stk.clear();
    sort(ps.begin(), ps.end());
    sort(ps.begin() + 1, ps.end(), comp(ps[0]));
    stk.push_back(ps[0]);
    stk.push_back(ps[1]);
    stk.push_back(ps[2]);
    for (int i = 3; i < ps.size(); i++) {
        while (true) {
            Point p2 = *(stk.end() - 1);
            Point p1 = *(stk.end() - 2);
            if (epssgn((p2 - p1) ^ (ps[i] - p2)) <= 0) stk.pop_back();
            else break;
        }
        stk.push_back(ps[i]);
    }
    return stk.size();
}
Grandpa's Estate
#include <iostream>
#include <vector>
#include <iomanip>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const double inf = 1e9;
const double eps = 1e-6;

struct Point {
    double x, y;
    Point(double a = 0, double b = 0) { x = a; y = b; }
    bool operator == (const Point& b) const {
        return x == b.x && y == b.y;
    }
    bool operator < (const Point& b) const {
        if (x == b.x) return y < b.y;
        return x < b.x;
    }
    friend ostream& operator << (ostream& os, const Point& p) {
        os << "(" << p.x << ", " << p.y << ")";
        return os;
    }
};

typedef Point Vector;

Vector operator + (Point a, Point b) { return Vector(a.x + b.x, a.y + b.y); }
Vector operator - (Point a, Point b) { return Vector(a.x - b.x, a.y - b.y); }
Vector operator * (Point a, double k) { return Vector(a.x*k, a.y*k); }
Vector operator * (double k, Point a) { return Vector(a.x*k, a.y*k); }
Vector operator / (Point a, double k) { return Vector(a.x / k, a.y / k); }
double operator * (Vector a, Vector b) { return a.x*b.x + a.y*b.y; }
double operator ^ (Vector a, Vector b) { return a.x*b.y - b.x*a.y; }
double len(Vector a) { return sqrt(a.x*a.x + a.y*a.y); }
Vector unit(Vector p) { return p * (1 / len(p)); }
double project(Vector a, Vector b) { return a * unit(b);}

struct Line {
    Point a, b;
    Line() {}
    Line(Point a, Point b) :a(a), b(b) {}
    double getx(double y) { return (y - a.y) / (b.y - a.y)*(b.x - a.x) + a.x; }
    double gety(double x) { return (x - a.x) / (b.x - a.x)*(b.y - a.y) + a.y; }
    friend ostream& operator <<(ostream& os, const Line & l){
        os << l.a << "->" << l.b;
        return os;
    }
};

int epssgn(double x) {
    if (fabs(x) < eps) return 0;
    else return x < 0 ? -1 : 1;
}

double dist(Point x, Point y) { return len(x - y); }
double dist(Point p, Line l) { return fabs((p - l.a) ^ (l.b - l.a)) / len(l.b - l.a);}
double area(Vector a, Vector b) { return a ^ b / 2;}

int SideOfLine(Point p, Point a, Point b) {
    double res = (b - a) ^ (p - a);
    if (epssgn(res) == 0) return 0;
    else if (res > 0) return 1;
    else return -1;
}

int SideOfLine(Point p, Line l) {
    return SideOfLine(p, l.a, l.b);
}

bool PointInSeg(Point p, Line l) {
    double tmp = (l.a - p) ^ (l.a - l.b);
    if (!epssgn(tmp) == 0) return false;
    if (epssgn(min(l.a.x, l.b.x) - p.x) <= 0 &&
        epssgn(p.x - max(l.a.x, l.b.x)) <= 0 &&
        epssgn(min(l.a.y, l.b.y) - p.y) <= 0 &&
        epssgn(p.y - max(l.a.y, l.b.y)) <= 0)
        return true;
    return false;
}

pair<int, Point> SegCrossSeg(Line s1, Line s2) {
    Point p1 = s1.a;
    Point p2 = s1.b;
    Point p3 = s2.a;
    Point p4 = s2.b;
    double a1 = area(p3 - p1, p4 - p1);
    double a2 = area(p4 - p2, p3 - p2);
    Point crossPoint = p1 + (p2 - p1)*(a1 / (a1 + a2));
    if (epssgn(((p2 - p1) ^ (p3 - p1))*((p2 - p1) ^ (p4 - p1))) < 0 &&
        epssgn(((p4 - p3) ^ (p1 - p3))*((p4 - p3) ^ (p2 - p3))) < 0)
        return make_pair(0, crossPoint); // standard cross
    if (epssgn((p2 - p1) ^ (p3 - p4)) != 0) {
        // 端点重合,不平行,不共线
        if (p1 == p3 || p1 == p4) return make_pair(1, p1);
        if (p2 == p3 || p2 == p4) return make_pair(1, p2);
        // s1端点在s2内部,不平行,不共线
        if (PointInSeg(p1, s2)) return make_pair(2, p1);
        if (PointInSeg(p2, s2)) return make_pair(2, p2);
        // s2端点在s1内部,不平行,不共线
        if (PointInSeg(p3, s1)) return make_pair(3, p3);
        if (PointInSeg(p4, s1)) return make_pair(3, p4);
        // s2所在直线与线段s1相交
        if (PointInSeg(crossPoint, s1)) return make_pair(8, crossPoint);
        // s1所在直线与线段s2相交
        if (PointInSeg(crossPoint, s2)) return make_pair(9, crossPoint);
        // 两直线相交
        return make_pair(4, crossPoint);
    }
    // 平行
    if (!epssgn(dist(p1, s2))) return make_pair(5, Point(0, 0)); 
    // 共线,有公共交点
    if (PointInSeg(p1, s2)) return make_pair(6, p1);
    if (PointInSeg(p2, s2)) return make_pair(6, p2);
    if (PointInSeg(p3, s1)) return make_pair(6, p3);
    if (PointInSeg(p4, s1)) return make_pair(6, p4);
    // 共线,无公共交点
    return make_pair(7, Point(0, 0));
}

// horizontal order graham
int graham(vector<Point>& ps, vector<Point>& stk) {
    int n = ps.size();
    if (n < 3) return 0;
    stk.clear();
    sort(ps.begin(), ps.end());
    stk.push_back(ps[0]);
    stk.push_back(ps[1]);
    for (int i = 2; i < n; i++) {
        while (stk.size() > 1) {
            Point p2 = *(stk.end() - 1);
            Point p1 = *(stk.end() - 2);
            if (epssgn((p2 - p1) ^ (ps[i] - p2)) < 0) stk.pop_back();
            else break;
        }
        stk.push_back(ps[i]);
    }
    int size = stk.size();
    stk.push_back(ps[n - 2]);
    for (int i = n - 3; i >= 0; i--) {
        while (stk.size() > size) {
            Point p2 = *(stk.end() - 1);
            Point p1 = *(stk.end() - 2);
            if (epssgn((p2 - p1) ^ (ps[i] - p2)) < 0) stk.pop_back();
            else break;
        }
        stk.push_back(ps[i]);
    }
    stk.pop_back();
    return stk.size();
}

const int maxn = 1005;
vector<Point> ps, hull;
int T, N, x, y;

int main() {
    cin >> T;
    while (T--) {
        cin >> N;
        ps.clear();
        for (int i = 0; i < N; i++) {
            cin >> x >> y;
            ps.push_back(Point(x, y));
        }
        if (N < 6) {
            cout << "NO" << endl;
            continue;
        }
        int s = graham(ps, hull);
        bool flag = true;
        for (int i = 0; i < s - 1; i++) {
            Line l(hull[i], hull[i + 1]);
            int cnt = 0;
            for (int j = 0; j < N; j++) if (SideOfLine(ps[j], l) == 0) cnt++;
            if (cnt < 3) {
                flag = false;
                break;
            }
        }
        if (flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
}
Most Distant Point from the Sea
#include <iostream>
#include <vector>
#include <iomanip>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const double inf = 1e9;
const double eps = 1e-6;

struct Point {
    double x, y;
    Point(double a = 0, double b = 0) { x = a; y = b; }
    bool operator == (const Point& b) const {
        return x == b.x && y == b.y;
    }
    bool operator < (const Point& b) const {
        if (x == b.x) return y < b.y;
        return x < b.x;
    }
    friend ostream& operator << (ostream& os, const Point& p) {
        os << "(" << p.x << ", " << p.y << ")";
        return os;
    }
};

typedef Point Vector;

Vector operator + (Point a, Point b) { return Vector(a.x + b.x, a.y + b.y); }
Vector operator - (Point a, Point b) { return Vector(a.x - b.x, a.y - b.y); }
Vector operator * (Point a, double k) { return Vector(a.x*k, a.y*k); }
Vector operator * (double k, Point a) { return Vector(a.x*k, a.y*k); }
Vector operator / (Point a, double k) { return Vector(a.x / k, a.y / k); }
double len(Vector a) { return sqrt(a.x*a.x + a.y*a.y); }
Vector unit(Vector p) { return p * (1 / len(p)); }
double project(Vector a, Vector b) { return a * unit(b);}
double operator * (Vector a, Vector b) { return a.x*b.x + a.y*b.y; }
double operator ^ (Vector a, Vector b) { return a.x*b.y - b.x*a.y; }

struct Line {
    Point a, b;
    Line() {}
    Line(Point a, Point b) :a(a), b(b) {}
    double getx(double y) { return (y - a.y) / (b.y - a.y)*(b.x - a.x) + a.x; }
    double gety(double x) { return (x - a.x) / (b.x - a.x)*(b.y - a.y) + a.y; }
    friend ostream& operator <<(ostream& os, const Line & l){
        os << l.a << "->" << l.b;
        return os;
    }
};

int epssgn(double x) {
    if (fabs(x) < eps) return 0;
    else return x < 0 ? -1 : 1;
}

double dist(Point x, Point y) { return len(x - y); }
double dist(Point p, Line l) { return fabs((p - l.a) ^ (l.b - l.a)) / len(l.b - l.a);}
double area(Vector a, Vector b) { return a ^ b / 2;}

int SideOfLine(Point p, Point a, Point b) {
    double res = (b - a) ^ (p - a);
    if (epssgn(res) == 0) return 0;
    else if (res > 0) return 1;
    else return -1;
}

int SideOfLine(Point p, Line l) {
    return SideOfLine(p, l.a, l.b);
}

bool PointInSeg(Point p, Line l) {
    double tmp = (l.a - p) ^ (l.a - l.b);
    if (!epssgn(tmp) == 0) return false;
    if (epssgn(min(l.a.x, l.b.x) - p.x) <= 0 &&
        epssgn(p.x - max(l.a.x, l.b.x)) <= 0 &&
        epssgn(min(l.a.y, l.b.y) - p.y) <= 0 &&
        epssgn(p.y - max(l.a.y, l.b.y)) <= 0)
        return true;
    return false;
}

pair<int, Point> SegCrossSeg(Line s1, Line s2) {
    Point p1 = s1.a;
    Point p2 = s1.b;
    Point p3 = s2.a;
    Point p4 = s2.b;
    double a1 = area(p3 - p1, p4 - p1);
    double a2 = area(p4 - p2, p3 - p2);
    Point crossPoint = p1 + (p2 - p1)*(a1 / (a1 + a2));
    if (epssgn(((p2 - p1) ^ (p3 - p1))*((p2 - p1) ^ (p4 - p1))) < 0 &&
        epssgn(((p4 - p3) ^ (p1 - p3))*((p4 - p3) ^ (p2 - p3))) < 0)
        return make_pair(0, crossPoint); // standard cross
    if (epssgn((p2 - p1) ^ (p3 - p4)) != 0) {
        // 端点重合,不平行,不共线
        if (p1 == p3 || p1 == p4) return make_pair(1, p1);
        if (p2 == p3 || p2 == p4) return make_pair(1, p2);
        // s1端点在s2内部,不平行,不共线
        if (PointInSeg(p1, s2)) return make_pair(2, p1);
        if (PointInSeg(p2, s2)) return make_pair(2, p2);
        // s2端点在s1内部,不平行,不共线
        if (PointInSeg(p3, s1)) return make_pair(3, p3);
        if (PointInSeg(p4, s1)) return make_pair(3, p4);
        // s2所在直线与线段s1相交
        if (PointInSeg(crossPoint, s1)) return make_pair(8, crossPoint);
        // s1所在直线与线段s2相交
        if (PointInSeg(crossPoint, s2)) return make_pair(9, crossPoint);
        // 两直线相交
        return make_pair(4, crossPoint);
    }
    // 平行
    if (!epssgn(dist(p1, s2))) return make_pair(5, Point(0, 0)); 
    // 共线,有公共交点
    if (PointInSeg(p1, s2)) return make_pair(6, p1);
    if (PointInSeg(p2, s2)) return make_pair(6, p2);
    if (PointInSeg(p3, s1)) return make_pair(6, p3);
    if (PointInSeg(p4, s1)) return make_pair(6, p4);
    // 共线,无公共交点
    return make_pair(7, Point(0, 0));
}

// HalfPlane, cut src with Line a->b's left half plane.
typedef vector<Point> Polygon;
int cutPolygon(const Polygon& src, Point a, Point b, Polygon& res) {
    int n = src.size();
    res.clear();
    for (int i = 0; i < n; i++) {
        Point c = src[i];
        Point d = src[(i + 1) % n]; // note %
        if (epssgn((b - a) ^ (c - a)) >= 0) res.push_back(c);
        pair<int, Point> r = SegCrossSeg(Line(c, d), Line(a, b));
        if (r.first == 0 || r.first == 8 || r.first == 3) res.push_back(r.second);
    }
    return res.size();
}

int N, x, y;
Polygon island, res;

bool check(double mid) {
    vector<Line> shrink;
    for (int i = 0; i < N; i++) {
        Line l(island[i], island[(i + 1) % N]);
        Vector vl = island[(i + 1) % N] - island[i];
        Vector v = unit(Vector(-vl.y, vl.x)) * mid; // vertical, length=mid
        Line ll(l.a + v, l.b + v); // push in
        shrink.push_back(ll);
    }
    int s;
    Polygon tmp = island;
    for (int i = 0; i < shrink.size(); i++) {
        s = cutPolygon(tmp, shrink[i].a, shrink[i].b, res);
        if (s == 0) break;
        tmp = res;
    }
    //cout <<"check " <<mid<<" :"<< res.size() << endl;
    return res.size() > 0;
}

int main() {
    while (cin >> N && N) {
        island.clear();
        for (int i = 0; i < N; i++) {
            cin >> x >> y;
            island.push_back(Point(x, y));
        }
        // eps binary search
        double left = 0, right = inf;
        while (epssgn(left-right)<0) {
            double mid = (left + right) / 2;
            if (check(mid)) left = mid + eps;
            else right = mid;
        }
        cout << fixed << setprecision(6) << left - eps << endl;
    }
}
Pipe
#include <iostream>
#include <vector>
#include <iomanip>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const double inf = 1e9;
const double eps = 1e-6;

struct Point {
    double x, y;
    Point(double a = 0, double b = 0) { x = a; y = b; }
    bool operator == (const Point& b) const {
        return x == b.x && y == b.y;
    }
    bool operator < (const Point& b) const {
        if (x == b.x) return y < b.y;
        return x < b.x;
    }
    friend ostream& operator << (ostream& os, const Point& p) {
        os << "(" << p.x << ", " << p.y << ")";
        return os;
    }
};

typedef Point Vector;

Vector operator + (Point a, Point b) { return Vector(a.x + b.x, a.y + b.y); }
Vector operator - (Point a, Point b) { return Vector(a.x - b.x, a.y - b.y); }
Vector operator * (Point a, double k) { return Vector(a.x*k, a.y*k); }
Vector operator * (double k, Point a) { return Vector(a.x*k, a.y*k); }
Vector operator / (Point a, double k) { return Vector(a.x / k, a.y / k); }
double operator * (Vector a, Vector b) { return a.x*b.x + a.y*b.y; }
double operator ^ (Vector a, Vector b) { return a.x*b.y - b.x*a.y; }
double len(Vector a) { return sqrt(a.x*a.x + a.y*a.y); }
Vector unit(Vector p) { return p * (1 / len(p)); }
double project(Vector a, Vector b) { return a * unit(b);}

struct Line {
    Point a, b;
    Line() {}
    Line(Point a, Point b) :a(a), b(b) {}
    double getx(double y) { return (y - a.y) / (b.y - a.y)*(b.x - a.x) + a.x; }
    double gety(double x) { return (x - a.x) / (b.x - a.x)*(b.y - a.y) + a.y; }
    friend ostream& operator <<(ostream& os, const Line & l){
        os << l.a << "->" << l.b;
        return os;
    }
};

int epssgn(double x) {
    if (fabs(x) < eps) return 0;
    else return x < 0 ? -1 : 1;
}

double dist(Point x, Point y) { return len(x - y); }
double dist(Point p, Line l) { return fabs((p - l.a) ^ (l.b - l.a)) / len(l.b - l.a);}
double area(Vector a, Vector b) { return a ^ b / 2;}

int SideOfLine(Point p, Point a, Point b) {
    double res = (b - a) ^ (p - a);
    if (epssgn(res) == 0) return 0;
    else if (res > 0) return 1;
    else return -1;
}

int SideOfLine(Point p, Line l) {
    return SideOfLine(p, l.a, l.b);
}

bool PointInSeg(Point p, Line l) {
    double tmp = (l.a - p) ^ (l.a - l.b);
    if (!epssgn(tmp) == 0) return false;
    if (epssgn(min(l.a.x, l.b.x) - p.x) <= 0 &&
        epssgn(p.x - max(l.a.x, l.b.x)) <= 0 &&
        epssgn(min(l.a.y, l.b.y) - p.y) <= 0 &&
        epssgn(p.y - max(l.a.y, l.b.y)) <= 0)
        return true;
    return false;
}

pair<int, Point> SegCrossSeg(Line s1, Line s2) {
    Point p1 = s1.a;
    Point p2 = s1.b;
    Point p3 = s2.a;
    Point p4 = s2.b;
    double a1 = area(p3 - p1, p4 - p1);
    double a2 = area(p4 - p2, p3 - p2);
    Point crossPoint = p1 + (p2 - p1)*(a1 / (a1 + a2));
    if (epssgn(((p2 - p1) ^ (p3 - p1))*((p2 - p1) ^ (p4 - p1))) < 0 &&
        epssgn(((p4 - p3) ^ (p1 - p3))*((p4 - p3) ^ (p2 - p3))) < 0)
        return make_pair(0, crossPoint); // standard cross
    if (epssgn((p2 - p1) ^ (p3 - p4)) != 0) {
        // 端点重合,不平行,不共线
        if (p1 == p3 || p1 == p4) return make_pair(1, p1);
        if (p2 == p3 || p2 == p4) return make_pair(1, p2);
        // s1端点在s2内部,不平行,不共线
        if (PointInSeg(p1, s2)) return make_pair(2, p1);
        if (PointInSeg(p2, s2)) return make_pair(2, p2);
        // s2端点在s1内部,不平行,不共线
        if (PointInSeg(p3, s1)) return make_pair(3, p3);
        if (PointInSeg(p4, s1)) return make_pair(3, p4);
        // s2所在直线与线段s1相交
        if (PointInSeg(crossPoint, s1)) return make_pair(8, crossPoint);
        // s1所在直线与线段s2相交
        if (PointInSeg(crossPoint, s2)) return make_pair(9, crossPoint);
        // 两直线相交
        return make_pair(4, crossPoint);
    }
    // 平行
    if (!epssgn(dist(p1, s2))) return make_pair(5, Point(0, 0)); 
    // 共线,有公共交点
    if (PointInSeg(p1, s2)) return make_pair(6, p1);
    if (PointInSeg(p2, s2)) return make_pair(6, p2);
    if (PointInSeg(p3, s1)) return make_pair(6, p3);
    if (PointInSeg(p4, s1)) return make_pair(6, p4);
    // 共线,无公共交点
    return make_pair(7, Point(0, 0));
}

const int maxn = 25;
Point up[maxn], down[maxn];
int N;
double x, y;

int main() {
    while (cin >> N && N) {
        for (int i = 1; i <= N; i++) {
            cin >> x >> y;
            up[i] = Point(x, y);
            down[i] = Point(x, y - 1);
        }
        double mxx = -inf;
        bool all = false;
        int i, j, k;
        for (i = 1; i <= N; i++) {
            for (j = 1; j <= N; j++) {
                if (i == j) continue;
                Line l(up[i], down[j]);
                for (k = 1; k <= N; k++) {
                    Line seg(up[k], down[k]);
                    if (!LineCrossSeg(l, seg).first) break;
                }
                if (k > N) {
                    all = true;
                    break;
                }
                else if (k > max(i, j)) {
                    Line seg1(up[k], up[k - 1]);
                    pair<int, Point> res = SegCrossSeg(l, seg1);
                    if (res.first <= 3 || res.first == 6 || res.first == 9) 
                        mxx = max(mxx, res.second.x);
                    Line seg2(down[k], down[k - 1]);
                    res = SegCrossSeg(l, seg2);
                    if (res.first <= 3 || res.first == 6 || res.first == 9) 
                        mxx = max(mxx, res.second.x);
                }
            }
            if (all) break;
        }
        if (all) cout << "Through all the pipe." << endl;
        else cout << fixed << setprecision(2) << mxx << endl;
    }
}