SYSU-1,URAL 1894,閩科夫斯基和(黑科技)

題目大題:給你兩個相交的凸包,其中一個可移動,問你至少移動多少可以讓兩個凸包分離ios

解:我艹我爲此寫了7k計算幾何仍是wa6了,後面去看discuz才知道是用一個閩科夫斯基和的黑科技。ide

閩科夫斯基和大概就是兩個點集的任意兩個點對相加獲得的一個新點集,差則是相減。這題用到了如下幾個性質:spa

  1:兩個凸包的閩科夫斯基差仍是凸包code

  2:兩個凸包若相交,那麼他們閩科夫斯基差的凸包覆蓋原點orm

易知答案是原點到凸包最短距離(能夠看做一個凸包平移這個向量,那麼他們的閩科夫斯基差就不過原點了,因此相離)blog

如今問題在於如何快速求差的凸包(定義求是nm的)。wiki告訴我一個性質,就是新凸包的向量組織是兩個舊凸包方向邊的和。string

因此對舊凸包一塊兒選一個方向,而後合併他們的向量,用新向量組合按順序掃一遍頭尾相接就獲得差凸包的形狀。接下來就是肯定位置。我大概yy了下(沒有嚴謹證實),凡是合併以後AB相間的兩個向量,他們的頭尾座標和一定是差凸包那個點的原座標,因此咱們比對一下位置凸包這個點的座標和實際座標的差平移一下便可。it

 

#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <complex>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <deque>

using namespace std;

const double EPS = 1e-8;

#define ABS(x) ((x)<0?(-(x)):(x))
#define SQR(x) ((x)*(x))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))

#define LSON(x) ((x)<<1)
#define RSON(x) (((x)<<1)+1)
#define LOWBIT(x) ((x)&(-(x)))
#define MAXN 111111
#define LL long long

int cmp(const double &x) {
    return x < -EPS ? -1 : (x > EPS ? 1 : 0);
}

struct point{
    double x, y;
    point(double a = 0, double b = 0): x(a), y(b) {}

    point operator + (const point &rhs) const {
        return point(x + rhs.x, y + rhs.y);
    }
    point operator - (const point &rhs) const {
        return point(x - rhs.x, y - rhs.y);
    }
    point operator * (const double &rhs) const {
        return point(x * rhs, y * rhs);
    }
    point operator / (const double &rhs) const {
        return point(x / rhs, y / rhs);
    }
    bool operator < (const point &rhs) const {
        if (cmp(x - rhs.x) == 0) return y < rhs.y;
        return x < rhs.x;
    }

    void read() {
        scanf("%lf%lf", &x, &y);
    }
    void write() const {
        printf("%lf %lf\n", x, y);
    }
    double norm() const {
        return sqrt(SQR(x) + SQR(y));
    }
};

double dot(const point &a, const point &b) {
    return a.x * b.x + a.y * b.y;
}

double det(const point &a, const point &b) {
    return a.x * b.y - a.y * b.x;
}

typedef point Point;
//#define Point point
typedef pair<Point, Point > Halfplane;
typedef vector<Point > Convex;

inline double arg(const point &a) {
    double res = atan2(a.y, a.x);
    return res;
}

#define cross(a,b) det(a,b)

void PointProjLine(const point &p, const point &s, const point &t, point &cp) {
    double r = dot((t-s), (p-s))/dot(t-s, t-s);
    cp = s + (t - s) * r;
}

int n, m;
Convex a, b, c;
double ans;

struct data{
    double a;
    point st, ed;
    int col;
    data() {}
    data(double aa, point b, point c, int d): a(aa), st(b), ed(c), col(d) {}
    bool operator < (const data &rhs) const {
        return a < rhs.a;
    }
};

vector <data > aa;
vector <point > key;

const double PI = acos(-1);

void init() {
    double ans = 1e30;
    Point x;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i) {
        x.read(); a.push_back(x);
    } a.push_back(a[0]);

    for (int i = 0; i < n; ++i) {
        aa.push_back(data(arg((a[i+1] - a[i])) + 2 * PI, a[i], a[i+1], 0));
    }

    for (int i = 0; i < m; ++i) {
        x.read(); b.push_back(x*-1);
    } b.push_back(b[0]);
    for (int i = 0; i < m; ++i) {
        aa.push_back(data(arg((b[i+1] - b[i])) + 2 * PI, b[i], b[i+1], 1));
    }
    sort(aa.begin(), aa.end());
}

double dist(const point &p, const point &s, const point &t) {
    point tt;
    PointProjLine(p, s, t, tt);
    return (p - tt).norm();
}

void solve() {
    point now = point(0, 0);
    aa.push_back(aa[0]);
    for (int i = 0; i < n+m; ++i) {
        now = now + (aa[i].ed - aa[i].st);
        key.push_back(now);
    }
    point dd;
    key.push_back(key[0]);

    for (int i = 0; i + 1 < n+m; ++i) {
        if (aa[i].col != aa[i+1].col) {
            dd = (aa[i].ed + aa[i+1].st) - key[i];
            break;
        }
    }
    for (int i = 0; i < key.size(); ++i) {
        key[i] = key[i] + dd;
    }
    ans = 1e30;
    for (int i = 0; i < n+m; ++i) {
        ans = min(ans, dist(point(0, 0), key[i], key[i+1]));
    }
}


int main() {
    freopen("test.txt", "r", stdin);
    init();
    solve();
    if (ans < 60) puts("0");
    else printf("%.8lf\n", max(0.0, ans - 60));
    return 0;
}
ural 1894
相關文章
相關標籤/搜索