Description
给定两个凸多边形 (A,B),询问 (B) 是否严格在 (A) 内。
Solution
对 (A,B) 的所有点构造非严格凸包,如果这个凸包等于 (B),则符合条件。
(方法真的挺妙的)
#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define fi first
#define se second
#define pb push_back
typedef double db;
const db eps = 1e-6;
const db pi = acos(-1);
int sign(db k)
{
if (k > eps) return 1;
else if (k < -eps) return -1;
return 0;
}
int cmp(db p1, db p2)
{
return sign(p1 - p2);
}
int inmid(db p1, db p2, db p3)
{
return sign(p1 - p3) * sign(p2 - p3) <= 0;
}
struct point
{
db x, y;
point operator + (const point& p1) const
{
return (point)
{
p1.x + x, p1.y + y
};
}
point operator - (const point& p1) const
{
return (point)
{
x - p1.x, y - p1.y
};
}
point operator * (db p1) const
{
return (point)
{
x* p1, y* p1
};
}
point operator / (db p1) const
{
return (point)
{
x / p1, y / p1
};
}
int operator == (const point& p1) const
{
return cmp(x, p1.x) == 0 && cmp(y, p1.y) == 0;
}
// 逆时针旋转
point turn(db p1)
{
return (point)
{
x* cos(p1) - y * sin(p1), x* sin(p1) + y * cos(p1)
};
}
point turn90()
{
return (point)
{
-y, x
};
}
bool operator < (const point p1) const
{
int a = cmp(x, p1.x);
if (a == -1) return 1;
else if (a == 1) return 0;
else return cmp(y, p1.y) == -1;
}
db abs()
{
return sqrt(x * x + y * y);
}
db abs2()
{
return x * x + y * y;
}
db dis(point p1)
{
return ((*this) - p1).abs();
}
point unit()
{
db w = abs();
return (point)
{
x / w, y / w
};
}
void scan()
{
double p1, p2;
scanf("%lf%lf", &p1, &p2);
x = p1;
y = p2;
}
void print()
{
printf("%.11lf %.11lf
", x, y);
}
db getw()
{
return atan2(y, x);
}
point getdel()
{
if (sign(x) == -1 || (sign(x) == 0 && sign(y) == -1)) return (*this) * (-1);
else return (*this);
}
int getP() const
{
return sign(y) == 1 || (sign(y) == 0 && sign(x) == -1);
}
};
int inmid(point p1, point p2, point p3)
{
return inmid(p1.x, p2.x, p3.x) && inmid(p1.y, p2.y, p3.y);
}
db cross(point p1, point p2)
{
return p1.x * p2.y - p1.y * p2.x;
}
db dot(point p1, point p2)
{
return p1.x * p2.x + p1.y * p2.y;
}
db rad(point p1, point p2)
{
return atan2(cross(p1, p2), dot(p1, p2));
}
// -pi -> pi
int compareangle(point p1, point p2)
{
return p1.getP() < p2.getP() || (p1.getP() == p2.getP() && sign(cross(p1, p2)) > 0);
}
point proj(point p1, point p2, point q) // q 到直线 p1,p2 的投影
{
point k = p2 - p1;
return p1 + k * (dot(q - p1, k) / k.abs2());
}
point reflect(point p1, point p2, point q)
{
return proj(p1, p2, q) * 2 - q;
}
int clockwise(point p1, point p2, point p3) // p1 p2 p3 逆时针 1 顺时针 -1 否则 0
{
return sign(cross(p2 - p1, p3 - p1));
}
int checkLL(point p1, point p2, point p3, point p4) // 求直线 (L) 线段 (S)p1,p2 和 p3,p4 的交点
{
return cmp(cross(p3 - p1, p4 - p1), cross(p3 - p2, p4 - p2)) != 0;
}
point getLL(point p1, point p2, point p3, point p4)
{
db w1 = cross(p1 - p3, p4 - p3), w2 = cross(p4 - p3, p2 - p3);
return (p1 * w2 + p2 * w1) / (w1 + w2);
}
int intersect(db l1, db r1, db l2, db r2)
{
if (l1 > r1) swap(l1, r1);
if (l2 > r2) swap(l2, r2);
return cmp(r1, l2) != -1 && cmp(r2, l1) != -1;
}
int checkSS(point p1, point p2, point p3, point p4)
{
return intersect(p1.x, p2.x, p3.x, p4.x) && intersect(p1.y, p2.y, p3.y, p4.y) &&
sign(cross(p3 - p1, p4 - p1)) * sign(cross(p3 - p2, p4 - p2)) <= 0 &&
sign(cross(p1 - p3, p2 - p3)) * sign(cross(p1 - p4, p2 - p4)) <= 0;
}
db disSP(point p1, point p2, point q)
{
point p3 = proj(p1, p2, q);
if (inmid(p1, p2, p3)) return q.dis(p3);
else return min(q.dis(p1), q.dis(p2));
}
db disSS(point p1, point p2, point p3, point p4)
{
if (checkSS(p1, p2, p3, p4)) return 0;
else return min(min(disSP(p1, p2, p3), disSP(p1, p2, p4)), min(disSP(p3, p4, p1), disSP(p3, p4, p2)));
}
int onS(point p1, point p2, point q)
{
return inmid(p1, p2, q) && sign(cross(p1 - q, p2 - p1)) == 0;
}
struct line
{
// p[0]->p[1]
point p[2];
line(point p1, point p2)
{
p[0] = p1;
p[1] = p2;
}
point& operator [] (int k)
{
return p[k];
}
int include(point k)
{
return sign(cross(p[1] - p[0], k - p[0])) > 0;
}
point dir()
{
return p[1] - p[0];
}
line push() // 向外 ( 左手边 ) 平移 eps
{
const db eps = 1e-6;
point delta = (p[1] - p[0]).turn90().unit() * eps;
return { p[0] - delta,p[1] - delta };
}
};
point getLL(line p1, line p2)
{
return getLL(p1[0], p1[1], p2[0], p2[1]);
}
int parallel(line p1, line p2)
{
return sign(cross(p1.dir(), p2.dir())) == 0;
}
int sameDir(line p1, line p2)
{
return parallel(p1, p2) && sign(dot(p1.dir(), p2.dir())) == 1;
}
int operator < (line p1, line p2)
{
if (sameDir(p1, p2)) return p2.include(p1[0]);
return compareangle(p1.dir(), p2.dir());
}
int checkpos(line p1, line p2, line p3)
{
return p3.include(getLL(p1, p2));
}
db area(vector<point> A)
{
db ans = 0;
for (int i = 0; i < A.size(); i++) ans += cross(A[i], A[(i + 1) % A.size()]);
return ans / 2;
}
int checkconvex(vector<point>A)
{
int n = A.size();
A.push_back(A[0]);
A.push_back(A[1]);
for (int i = 0; i < n; i++) if (sign(cross(A[i + 1] - A[i], A[i + 2] - A[i])) == -1) return 0;
return 1;
}
int contain(vector<point>A, point q)
{
int pd = 0;
A.push_back(A[0]);
for (int i = 1; i < A.size(); i++)
{
point u = A[i - 1], v = A[i];
if (onS(u, v, q)) return 1;
if (cmp(u.y, v.y) > 0) swap(u, v);
if (cmp(u.y, q.y) >= 0 || cmp(v.y, q.y) < 0) continue;
if (sign(cross(u - v, q - v)) < 0) pd ^= 1;
}
return pd << 1;
}
vector<point> ConvexHull(vector<point>A, int flag = 1)
{
int n = A.size();
vector<point>ans(n * 2);
sort(A.begin(), A.end());
int now = -1;
for (int i = 0; i < A.size(); i++)
{
while (now > 0 && sign(cross(ans[now] - ans[now - 1], A[i] - ans[now - 1])) < flag) now--;
ans[++now] = A[i];
}
int pre = now;
for (int i = n - 2; i >= 0; i--)
{
while (now > pre && sign(cross(ans[now] - ans[now - 1], A[i] - ans[now - 1])) < flag) now--;
ans[++now] = A[i];
}
ans.resize(now);
return ans;
}
db convexDiameter(vector<point>A)
{
int now = 0, n = A.size();
db ans = 0;
for (int i = 0; i < A.size(); i++)
{
now = max(now, i);
while (1)
{
db p1 = A[i].dis(A[now % n]), p2 = A[i].dis(A[(now + 1) % n]);
ans = max(ans, max(p1, p2));
if (p2 > p1) now++;
else break;
}
}
return ans;
}
vector<point> convexcut(vector<point>A, point p1, point p2)
{
int n = A.size();
A.push_back(A[0]);
vector<point>ans;
for (int i = 0; i < n; i++)
{
int w1 = clockwise(p1, p2, A[i]), w2 = clockwise(p1, p2, A[i + 1]);
if (w1 >= 0) ans.push_back(A[i]);
if (w1 * w2 < 0) ans.push_back(getLL(p1, p2, A[i], A[i + 1]));
}
return ans;
}
int checkPoS(vector<point>A, point p1, point p2)
{
// 多边形 A 和直线 ( 线段 )p1->p2 严格相交 , 注释部分为线段
struct ins
{
point m, u, v;
int operator < (const ins& k) const
{
return m < k.m;
}
};
vector<ins>B;
//if (contain(A,p1)==2||contain(A,p2)==2) return 1;
vector<point>poly = A;
A.push_back(A[0]);
for (int i = 1; i < A.size(); i++) if (checkLL(A[i - 1], A[i], p1, p2))
{
point m = getLL(A[i - 1], A[i], p1, p2);
if (inmid(A[i - 1], A[i], m)/*&&inmid(p1,p2,m)*/) B.push_back((ins)
{
m, A[i - 1], A[i]
});
}
if (B.size() == 0) return 0;
sort(B.begin(), B.end());
int now = 1;
while (now < B.size() && B[now].m == B[0].m) now++;
if (now == B.size()) return 0;
int flag = contain(poly, (B[0].m + B[now].m) / 2);
if (flag == 2) return 1;
point d = B[now].m - B[0].m;
for (int i = now; i < B.size(); i++)
{
if (!(B[i].m == B[i - 1].m) && flag == 2) return 1;
int tag = sign(cross(B[i].v - B[i].u, B[i].m + d - B[i].u));
if (B[i].m == B[i].u || B[i].m == B[i].v) flag += tag;
else flag += tag * 2;
}
//return 0;
return flag == 2;
}
int checkinp(point r, point l, point m)
{
if (compareangle(l, r))
{
return compareangle(l, m) && compareangle(m, r);
}
return compareangle(l, m) || compareangle(m, r);
}
int checkPosFast(vector<point>A, point p1, point p2) // 快速检查线段是否和多边形严格相交
{
if (contain(A, p1) == 2 || contain(A, p2) == 2) return 1;
if (p1 == p2) return 0;
A.push_back(A[0]);
A.push_back(A[1]);
for (int i = 1; i + 1 < A.size(); i++)
if (checkLL(A[i - 1], A[i], p1, p2))
{
point now = getLL(A[i - 1], A[i], p1, p2);
if (inmid(A[i - 1], A[i], now) == 0 || inmid(p1, p2, now) == 0) continue;
if (now == A[i])
{
if (A[i] == p2) continue;
point pre = A[i - 1], ne = A[i + 1];
if (checkinp(pre - now, ne - now, p2 - now)) return 1;
}
else if (now == p1)
{
if (p1 == A[i - 1] || p1 == A[i]) continue;
if (checkinp(A[i - 1] - p1, A[i] - p1, p2 - p1)) return 1;
}
else if (now == p2 || now == A[i - 1]) continue;
else return 1;
}
return 0;
}
// 拆分凸包成上下凸壳 凸包尽量都随机旋转一个角度来避免出现相同横坐标
// 尽量特判只有一个点的情况 凸包逆时针
void getUDP(vector<point>A, vector<point>& U, vector<point>& D)
{
db l = 1e100, r = -1e100;
for (int i = 0; i < A.size(); i++) l = min(l, A[i].x), r = max(r, A[i].x);
int wherel, wherer;
for (int i = 0; i < A.size(); i++) if (cmp(A[i].x, l) == 0) wherel = i;
for (int i = A.size(); i; i--) if (cmp(A[i - 1].x, r) == 0) wherer = i - 1;
U.clear();
D.clear();
int now = wherel;
while (1)
{
D.push_back(A[now]);
if (now == wherer) break;
now++;
if (now >= A.size()) now = 0;
}
now = wherel;
while (1)
{
U.push_back(A[now]);
if (now == wherer) break;
now--;
if (now < 0) now = A.size() - 1;
}
}
// 需要保证凸包点数大于等于 3,2 内部 ,1 边界 ,0 外部
int containCoP(const vector<point>& U, const vector<point>& D, point k)
{
db lx = U[0].x, rx = U[U.size() - 1].x;
if (k == U[0] || k == U[U.size() - 1]) return 1;
if (cmp(k.x, lx) == -1 || cmp(k.x, rx) == 1) return 0;
int where1 = lower_bound(U.begin(), U.end(), (point)
{
k.x, -1e100
}) - U.begin();
int where2 = lower_bound(D.begin(), D.end(), (point)
{
k.x, -1e100
}) - D.begin();
int w1 = clockwise(U[where1 - 1], U[where1], k), w2 = clockwise(D[where2 - 1], D[where2], k);
if (w1 == 1 || w2 == -1) return 0;
else if (w1 == 0 || w2 == 0) return 1;
return 2;
}
// d 是方向 , 输出上方切点和下方切点
pair<point, point> getTangentCow(const vector<point>& U, const vector<point>& D, point d)
{
if (sign(d.x) < 0 || (sign(d.x) == 0 && sign(d.y) < 0)) d = d * (-1);
point whereU, whereD;
if (sign(d.x) == 0) return mp(U[0], U[U.size() - 1]);
int l = 0, r = U.size() - 1, ans = 0;
while (l < r)
{
int mid = l + r >> 1;
if (sign(cross(U[mid + 1] - U[mid], d)) <= 0) l = mid + 1, ans = mid + 1;
else r = mid;
}
whereU = U[ans];
l = 0, r = D.size() - 1, ans = 0;
while (l < r)
{
int mid = l + r >> 1;
if (sign(cross(D[mid + 1] - D[mid], d)) >= 0) l = mid + 1, ans = mid + 1;
else r = mid;
}
whereD = D[ans];
return mp(whereU, whereD);
}
// 先检查 contain, 逆时针给出
pair<point, point> getTangentCoP(const vector<point>& U, const vector<point>& D, point k)
{
db lx = U[0].x, rx = U[U.size() - 1].x;
if (k.x < lx)
{
int l = 0, r = U.size() - 1, ans = U.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, U[mid], U[mid + 1]) == 1) l = mid + 1;
else ans = mid, r = mid;
}
point w1 = U[ans];
l = 0, r = D.size() - 1, ans = D.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, D[mid], D[mid + 1]) == -1) l = mid + 1;
else ans = mid, r = mid;
}
point w2 = D[ans];
return mp(w1, w2);
}
else if (k.x > rx)
{
int l = 1, r = U.size(), ans = 0;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, U[mid], U[mid - 1]) == -1) r = mid;
else ans = mid, l = mid + 1;
}
point w1 = U[ans];
l = 1, r = D.size(), ans = 0;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, D[mid], D[mid - 1]) == 1) r = mid;
else ans = mid, l = mid + 1;
}
point w2 = D[ans];
return mp(w2, w1);
}
else
{
int where1 = lower_bound(U.begin(), U.end(), (point)
{
k.x, -1e100
}) - U.begin();
int where2 = lower_bound(D.begin(), D.end(), (point)
{
k.x, -1e100
}) - D.begin();
if ((k.x == lx && k.y > U[0].y) || (where1 && clockwise(U[where1 - 1], U[where1], k) == 1))
{
int l = 1, r = where1 + 1, ans = 0;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, U[mid], U[mid - 1]) == 1) ans = mid, l = mid + 1;
else r = mid;
}
point w1 = U[ans];
l = where1, r = U.size() - 1, ans = U.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, U[mid], U[mid + 1]) == 1) l = mid + 1;
else ans = mid, r = mid;
}
point w2 = U[ans];
return mp(w2, w1);
}
else
{
int l = 1, r = where2 + 1, ans = 0;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, D[mid], D[mid - 1]) == -1) ans = mid, l = mid + 1;
else r = mid;
}
point w1 = D[ans];
l = where2, r = D.size() - 1, ans = D.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (clockwise(k, D[mid], D[mid + 1]) == -1) l = mid + 1;
else ans = mid, r = mid;
}
point w2 = D[ans];
return mp(w1, w2);
}
}
}
signed main()
{
int n,m;
cin>>n;
vector<point> a,b,c;
for(int i=1;i<=n;i++)
{
point tmp;
tmp.scan();
a.push_back(tmp);
c.push_back(tmp);
}
cin>>m;
for(int i=1;i<=m;i++)
{
point tmp;
tmp.scan();
b.push_back(tmp);
c.push_back(tmp);
}
c=ConvexHull(c,0);
sort(a.begin(),a.end());
sort(c.begin(),c.end());
int flag=1;
if(a.size()!=c.size())
{
flag=0;
}
else
{
for(int i=0;i<a.size();i++)
{
if(!(a[i]==c[i]))
{
flag=0;
break;
}
}
}
if(flag) puts("YES");
else puts("NO");
}