题目大题:给你两个相交的凸包,其中一个可移动,问你至少移动多少能够让两个凸包分离
解:我艹我为此写了7k计算几何还是wa6了,后面去看discuz才知道是用一个闽科夫斯基和的黑科技。
闽科夫斯基和大概就是两个点集的任意两个点对相加得到的一个新点集,差则是相减。这题用到了以下几个性质:
1:两个凸包的闽科夫斯基差还是凸包
2:两个凸包若相交,那么他们闽科夫斯基差的凸包覆盖原点
易知答案是原点到凸包最短距离(可以看作一个凸包平移这个向量,那么他们的闽科夫斯基差就不过原点了,所以相离)
现在问题在于如何快速求差的凸包(定义求是nm的)。wiki告诉我一个性质,就是新凸包的向量组织是两个旧凸包方向边的和。
所以对旧凸包一起选一个方向,然后合并他们的向量,用新向量组合按顺序扫一遍头尾相接就得到差凸包的形状。接下来就是确定位置。我大概yy了下(没有严谨证明),凡是合并之后AB相间的两个向量,他们的头尾坐标和必定是差凸包那个点的原坐标,所以我们比对一下位置凸包这个点的坐标和实际坐标的差平移一下即可。
#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 ", 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 ", max(0.0, ans - 60)); return 0; }