计算几何

……我好菜啊……

AOJ CGL_1_A

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
struct Point
{
    double x, y;
    Point(int a, int b){x = a, y = b;}
    Point(double a = .0, double b = .0){x = a, y = b;}
    Point operator+(Point q){return Point(x + q.x, y + q.y);}
    Point operator-(Point q){return Point(x - q.x, y - q.y);}
    Point operator*(double a){return Point(x * a, y * a);}
} P1, P2, P;
struct Segment
{
    Point a, b;
    Segment(Point x, Point y){a = x, b = y;}
};
#define sqr(x) ((x) * (x))
inline double dot(Point x, Point y){return x.x * y.x + x.y * y.y;}
inline double norm(Point s){return dot(s, s);}
int main()
{
    int x1, y1, x2, y2, x, y; read(x1, y1), read(x2, y2); P1 = Point(x1, y1), P2 = Point(x2, y2);
    Segment S = Segment(P1, P2);
    int q; read(q);
    while(q--)
    {
        read(x, y); P = Point(x, y);
        double r = dot(P - S.a, S.b - S.a) / norm(S.b - S.a);
        Point x = S.a + (S.b - S.a) * r;
        printf("%.9lf %.9lf\n", x.x, x.y);
    }
    return 0;
}

AOJ CGL_1_C

ccw.

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
struct Point
{
    double x, y;
    Point(int a, int b){x = a, y = b;}
    Point(double a = .0, double b = .0){x = a, y = b;}
    Point operator+(const Point& r){return Point(x + r.x, y + r.y);}
    Point operator-(const Point& r){return Point(x - r.x, y - r.y);}
    Point operator*(double r){return Point(x * r, y * r);}
    double operator*(const Point& r){return x * r.y - y * r.x;}
};
typedef Point Vector;
double dot(Vector l, Vector r){return l.x * r.x + l.y * r.y;}
double norm(Vector l){return dot(l, l);}
char* ccw(Point x, Point y, Point z)
{
    double cross = (y - x) * (z - x);
    if(cross > 0) return "COUNTER_CLOCKWISE";
    if(cross < 0) return "CLOCKWISE";
    if(dot(y - x, z - x) < 0) return "ONLINE_BACK";
    if(norm(y - x) < norm(z - x)) return "ONLINE_FRONT";
    return "ON_SEGMENT";
}
int main()
{
    int x0, y0, x1, y1, x, y; read(x0, y0), read(x1, y1);
    int q; read(q);
    while(q--)
    {
        read(x, y);
        puts(ccw(Point(x0, y0), Point(x1, y1), Point(x, y)));
    }
    return 0;
}

AOJ CGL_2_C

求线段交点。式子很妙。

Code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
struct Point
{
    double x, y;
    Point(int a, int b){x = a, y = b;}
    Point(double a = .0, double b = .0){x = a, y = b;}
    Point operator+(const Point& r){return Point(x + r.x, y + r.y);}
    Point operator-(const Point& r){return Point(x - r.x, y - r.y);}
    Point operator*(double r){return Point(x * r, y * r);}
    double operator*(const Point& r){return x * r.y - y * r.x;}
};
typedef Point Vector;
inline double norm(Vector l){return l.x * l.x + l.y * l.y;}
inline double abs(Vector l){return sqrt(norm(l));}
inline Vector Norm(Vector a){return a * (1 / abs(a));}
inline Point CrossPoint(Point x, Vector u, Point y, Vector v)
{Vector w = x - y;return x + u * ((v * w) / (u * v));}
int main()
{
    int q, x0, y0, x1, y1, x2, y2, x3, y3; read(q);
    while(q--)
    {
        read(x0, y0), read(x1, y1), read(x2, y2), read(x3, y3);
        Point ret = CrossPoint(Point(x0, y0), (Point(x1, y1) - Point(x0, y0)), Point(x2, y2), (Point(x3, y3) - Point(x2, y2)));
        printf("%.10lf %.10lf\n", ret.x, ret.y);
    }
    return 0;
}

AOJ CGL_3_C

点包含。统计过该点平行于x轴的直线过边界的交点数量的奇偶即可。

Code

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
const double eps = 1e-10;
const int maxn = 1e3;
struct Point
{
    double x, y;
    Point(int a, int b){x = a, y = b;}
    Point(double a = .0, double b = .0){x = a, y = b;}
    Point operator+(const Point& r){return Point(x + r.x, y + r.y);}
    Point operator-(const Point& r){return Point(x - r.x, y - r.y);}
    Point operator*(double r){return Point(r * x, r * y);}
    double operator*(const Point& r){return x * r.y - y * r.x;}
} g[maxn];
int n; 
typedef Point Vector;
inline double dot(Vector l, Vector r){return l.x * r.x + l.y * r.y;}
int contains(Point p)
{
    bool x = false;
    for(int i = 0; i < n; ++i)
    {
        Vector a = g[i] - p, b = g[(i + 1) % n] - p;
        double cross = a * b;
        if(abs(cross) < eps && dot(a, b) < eps) return 1;
        if(a.y > b.y) swap(a, b), cross = a * b;
        if(a.y < eps && eps < b.y && cross > eps) x = !x;
    }
    return x ? 2 : 0;
}
int main()
{
    read(n);
    for(int i = 0, x, y; i < n; ++i) read(x, y), g[i] = Point(x, y);
    int q; read(q);
    while(q--)
    {
        int x, y; read(x, y);
        printf("%d\n", contains(Point(x, y)));
    }
    return 0;
}

AOJ DSL_2_C

平面范围查询。k-d tree 基本应用。

AOJ CGL_4_A

求凸包。输出有特殊格式。

Code

#include <cstdio>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
const int maxn = 1e5 + 5;
struct P
{
    int x, y;
    P(int a = 0, int b = 0) {x = a, y = b;}
    //P(double a = .0, double b = .0){x = a, y = b;}
    P operator-(const P& r){return P(r.x - x, r.y - y);}
    int operator*(const P& r){return x * r.y - y * r.x;}
    bool operator<(const P& r)const{return x == r.x ? y < r.y : x < r.x;}
} p[maxn];
int s[maxn << 1], t;
int main()
{
    int n; read(n);
    for(int i = 1; i <= n; ++i) read(p[i].x, p[i].y);
    sort(p + 1, p + n + 1);
    // if(n == 3)
    // {
    //     printf("%d\n%d %d\n%d %d\n%d %d\n", 3, p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y);
    //     return 0;
    // }
    s[0] = 1, s[1] = 2, t = 2;
    for(int i = 3; i <= n; ++i)
    {
        int ret;
        while(t > 1 && (ret = (p[i] - p[s[t - 2]]) * (p[s[t - 1]] - p[s[t - 2]])) > 0) --t;
        s[t++] = i;
    }
    int tt = t - 1;
    s[t++] = n - 1; //fa2[n] = n + 1;
    for(int i = n - 2; i; --i)
    {
        while(t > tt && (p[i] - p[s[t - 2]]) * (p[s[t - 1]] - p[s[t - 2]]) > 0) --t; 
        s[t++] = i;
    }
    --t;
    printf("%d\n", t);
    int num = 0;
    for(int i = 0; i < t; ++i) if(p[s[i]].y < p[s[num]].y) num = i;
    for(int i = num; i < t; ++i) printf("%d %d\n", p[s[i]].x, p[s[i]].y);
    for(int i = 0; i < num; ++i) printf("%d %d\n", p[s[i]].x, p[s[i]].y);
    return 0;
}

AOJ CGL_5_A

平面最小点对。证明很妙。有空补。

Code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
const int maxn = 1e5 + 5;
const double eps = 1e-7, INF = 100000000000000000000;
struct P{double x, y; bool operator<(const P& r)const{return abs(x - r.x) < eps ? y < r.y : x < r.x;}} p[maxn], temp[maxn];
inline double dis(P a, P b){return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));}
int n;
inline bool cmp(P a, P b){return a.y < b.y;}
double dc(int L = 1, int R = n)
{
    if(L == R) return INF;
    if(L + 1 == R) return dis(p[L], p[R]);
    int M = (L + R) >> 1;
    double ans = min(dc(L, M), dc(M + 1, R));
    int k = 0;
    for(int i = L; i <= R; ++i) if(abs(p[M].x - p[i].x) <= ans)
        temp[k++] = p[i];
    sort(temp, temp + k, cmp);
    for(int i = 0; i < k; ++i) for(int j = i + 1; j < k && temp[j].y - temp[i].y <= ans; ++j)
        ans = min(ans, dis(temp[i], temp[j]));
    return ans;
}
int main()
{
    read(n);
    for(int i = 1; i <= n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
    sort(p + 1, p + n + 1);
    printf("%.7lf\n", dc());
    return 0;
}

Vijos 1012

同上。

Code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
const int maxn = 1e5 + 5;
const double eps = 1e-7, INF = 100000000000000000000;
struct P{double x, y; bool operator<(const P& r)const{return abs(x - r.x) < eps ? y < r.y : x < r.x;}} p[maxn], temp[maxn];
inline double dis(P a, P b){return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));}
int n;
inline bool cmp(P a, P b){return a.y < b.y;}
double dc(int L = 1, int R = n)
{
    if(L == R) return INF;
    if(L + 1 == R) return dis(p[L], p[R]);
    int M = (L + R) >> 1;
    double ans = min(dc(L, M), dc(M + 1, R));
    int k = 0;
    for(int i = L; i <= R; ++i) if(abs(p[M].x - p[i].x) <= ans)
        temp[k++] = p[i];
    sort(temp, temp + k, cmp);
    for(int i = 0; i < k; ++i) for(int j = i + 1; j < k && temp[j].y - temp[i].y <= ans; ++j)
        ans = min(ans, dis(temp[i], temp[j]));
    return ans;
}
int main()
{
    read(n);
    for(int i = 1; i <= n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
    sort(p + 1, p + n + 1);
    printf("%.3lf\n", dc());
    return 0;
}

POJ 3714

平面最小点对,要求两点属于不同集合。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1e5 + 5, INF = 0x7fffffff;
struct P{double x, y; int t; 
    bool operator<(const P&r)const{return x == r.x ? (y == r.y ? t < r.t : y < r.y) : x < r.x;}
    bool operator==(const P& r)const{return x == r.x && y == r.y && t == r.x;}
} p[maxn << 1], tmp[maxn << 1];
inline double dis(P a, P b){return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));}
inline bool cmp(P a, P b){return a.y < b.y;}
int n;
double dc(int L = 1, int R = n)
{
    if(L == R || (L + 1 == R && p[L].t == p[R].t)) return INF;
    if(L + 1 == R) return dis(p[L], p[R]);
    int M = (L + R) >> 1;
    double ans = min(dc(L, M), dc(M + 1, R));
    int k = 0;
    for(int i = L; i <= R; ++i) if(abs(p[M].x - p[L].x) <= ans)
        tmp[k++] = p[i];
    sort(tmp, tmp + k, cmp);
    for(int i = 0; i < k; ++i) for(int j = i; j < k && tmp[j].y - tmp[i].y < ans; ++j) if(tmp[i].t != tmp[j].t)
        ans = min(ans, dis(tmp[i], tmp[j]));
    return ans;
}
int main()
{
    int t; scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y), p[i].t = 0;
        n += n;
        for(int i = n / 2 + 1; i <= n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y), p[i].t = 1;
        sort(p + 1, p + n + 1);
        //n = unique(p + 1, p + n + 1) - p;
        printf("%.3lf\n", dc());
    }
    return 0;
}

AOJ CGL_4_B

卡壳裸题。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 8e4 + 5;
struct P
{
    double x, y;
    P(double a = .0, double b = .0){x = a, y = b;}
    P operator-(const P& r){return P(x - r.x, y - r.y);}
    double operator*(const P& r){return x * r.y - y * r.x;}
    bool operator<(const P& r){return x == r.x ? y < r.y : x < r.x;}
} p[maxn];
inline double dis(P a, P b){return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));}
int main()
{
    int n; scanf("%d", &n);
    for(int i = 0; i < n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
    int i = 0, j = 0;
    for(int k = 0; k < n; ++k)
    {
        if(p[k] < p[i]) i = k;
        if(p[j] < p[k]) j = k;
    }
    int si = i, sj = j;
    double ret = .0;
    while(i != sj || j != si)
    {
        ret = max(ret, dis(p[i], p[j]));
        if((p[(i + 1) % n] - p[i]) * (p[(j + 1) % n] - p[j]) < 0) (++i) %= n;
        else (++j) %= n;
    }
    printf("%.7lf\n", ret);
    return 0;
}

POJ 2187

求包后卡壳。注意退化情况。

Code

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
const int maxn = 5e4 + 5;
struct P
{
    int x, y;
    P(int a = 0, int b = 0){x = a, y = b;}
    P operator-(const P& r){return P(x - r.x, y - r.y);}
    int operator*(const P& r){return x * r.y - y * r.x;}
    bool operator<(const P& r)const{return x == r.x ? y < r.y : x < r.x;}
} p[maxn], h[maxn];
inline int dis(P l, P r){return (r.x - l.x) * (r.x - l.x) + (r.y - l.y) * (r.y - l.y);}
int main()
{
    int n; read(n);
    for(int i = 0; i < n; ++i) read(p[i].x, p[i].y);
    sort(p, p + n);
    h[0] = p[0], h[1] = p[1]; int k = 2;
    for(int i = 2; i < n; ++i)
    {
        while(k > 1 && (p[i] - h[k - 2]) * (h[k - 1] - h[k - 2]) <= 0) --k;
        h[k++] = p[i];
    }
    int kk = k; h[kk++] = p[n - 2];
    for(int i = n - 3; ~i; --i)
    {
        while(kk > k && (p[i] - h[kk - 2]) * (h[kk - 1] - h[kk - 2]) <= 0) --kk;
        h[kk++] = p[i];
    }
    if(kk > 2) kk--;
    if(kk == 2)
    {
        printf("%d\n", dis(h[0], h[1]));
        return 0;
    }
    int i = 0, j = 0;
    for(int l = 0; l < kk; ++l){if(h[l] < h[i]) i = l; if(h[j] < h[l]) j = l;}
    int si = i, sj = j, ret = 0;
    while(i != sj || j != si)
    {
        ret = max(ret, dis(h[i], h[j]));
        if((h[(i + 1) % kk] - h[i]) * (h[(j + 1) % kk] - h[j]) > 0) (++i) %= kk;
        else (++j) %= kk;
    }
    printf("%d\n", ret);
}

LA 4728

求出各个端点后上凸包直径。

Code

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}
const int maxn = 5e5 + 5;
struct P
{
    int x, y;
    P(int a = 0, int b = 0){x = a, y = b;}
    P operator-(const P& r){return P(x - r.x, y - r.y);}
    int operator*(const P& r){return x * r.y - y * r.x;}
    bool operator<(const P& r)const{return x == r.x ? y < r.y : x < r.x;}
} p[maxn], h[maxn];
inline int dis(P l, P r){return (r.x - l.x) * (r.x - l.x) + (r.y - l.y) * (r.y - l.y);}
int main()
{
    int t; read(t);
    while(t--)
    {
        int n; read(n);
        for(int i = 0, x, y, w; i < n; ++i) 
            read(x, y, w), p[i * 4] = P(x, y), p[i * 4 + 1] = P(x + w, y), p[i * 4 + 2] = P(x, y + w), p[i * 4 + 3] = P(x + w, y + w);
        n *= 4;
        sort(p, p + n);
        h[0] = p[0], h[1] = p[1]; int k = 2;
        for(int i = 2; i < n; ++i)
        {
            while(k > 1 && (p[i] - h[k - 2]) * (h[k - 1] - h[k - 2]) <= 0) --k;
            h[k++] = p[i];
        }
        int kk = k; h[kk++] = p[n - 2];
        for(int i = n - 3; ~i; --i)
        {
            while(kk > k && (p[i] - h[kk - 2]) * (h[kk - 1] - h[kk - 2]) <= 0) --kk;
            h[kk++] = p[i];
        }
        if(kk > 2) kk--;
        if(kk == 2)
        {
            printf("%d\n", dis(h[0], h[1]));
            return 0;
        }
        int i = 0, j = 0;
        for(int l = 0; l < kk; ++l){if(h[l] < h[i]) i = l; if(h[j] < h[l]) j = l;}
        int si = i, sj = j, ret = 0;
        while(i != sj || j != si)
        {
            ret = max(ret, dis(h[i], h[j]));
            if((h[(i + 1) % kk] - h[i]) * (h[(j + 1) % kk] - h[j]) > 0) (++i) %= kk;
            else (++j) %= kk;
        }
        printf("%d\n", ret);
    }
    return 0;
}

标签: computational geometry

添加新评论