1001. 度度熊保护村庄
这题是要求包含凸包的最小点数的凸包。假设凸包是A型点,外围点是B型点。那么如果对于所有Bi点对于凸包A做右切线,那么如果需要Bi点包围凸包A,显然是切线右边的点才可以和Bi相连。于是这时候是可以n^3暴力的。但是,其实对于Bi点来说,它能连到的最好的点,显然是所有满足的点中,右切线切点最远的哪个点是最优的。
对于Bi来说,Bj和Bk都是可选点。但是显然Bk是比较优的。于是找到每个点的nxt之后。只需要知道转一圈需要最少几个点就好了。于是问题n^2就已经可以解决了。但是其实可以更快。比如找nxt那块可以O(n).然后整体复杂度可以减少到nlogn.
其中代码是由@Alwayswet写的,可以看到只需要0ms就可以通过该题目了。
#include
using namespace std;
struct Pnt {
int x, y;
Pnt() {}
Pnt(int x, int y) : x(x), y(y) {}
Pnt operator-(const Pnt& a) {
return Pnt(x - a.x, y - a.y);
}
int operator*(const Pnt& a) {
return x * a.y - y * a.x;
}
int operator^(const Pnt& a) {
return x * a.x + y * a.y;
}
bool operator==(const Pnt& a) {
return x == a.x && y == a.y;
}
void input() {
cin >> x >> y;
}
} p[505], q[505], res[505];
double mult(Pnt sp, Pnt ep, Pnt op) {
return (sp.x - op.x) * (ep.y - op.y) - (ep.x - op.x) * (sp.y - op.y);
}
bool operator<(const Pnt &l, const Pnt &r) {
return l.y < r.y || (l.y == r.y && l.x < r.x);
}
int graham(Pnt pnt[], int n, Pnt res[]) {
int i, len, top = 1;
sort(pnt, pnt + n);
if(n == 0) return 0;
res[0] = pnt[0];
if(n == 1) return 1;
res[1] = pnt[1];
if(n == 2) return 2;
res[2] = pnt[2];
for(i = 2; i < n; ++i) {
while(top && mult(pnt[i], res[top], res[top - 1]) >= 0) --top;
res[++top] = pnt[i];
}
len = top;
res[++top] = pnt[n - 2];
for(i = n - 3; i >= 0; --i) {
while(top != len && mult(pnt[i], res[top], res[top - 1]) >= 0) --top;
res[++top] = pnt[i];
}
return top;
}
bool pnt_on_seg(Pnt p, Pnt l1, Pnt l2) {
return ((l1 - p) * (l2 - p)) == 0 && ((l1 - p) ^ (l2 - p)) <= 0;
}
int pnt_in_ploy(Pnt tp[], int n, Pnt pnt) {
for(int i = 0; i < n; ++i) {
int s = (pnt - tp[i]) * (tp[i + 1] - tp[i]);
if(s == 0) return 0;
if(pnt == tp[i]) return 2;
if(s > 0) return -1;
}
return 1;
}
bool check(Pnt tp[], int n, Pnt pt[], int m) {
for(int i = 0; i < n; ++i) {
if(pnt_in_ploy(pt, m, tp[i]) < 0) return false;
}
return true;
}
bool judge(Pnt u, Pnt v, Pnt p1, Pnt p2, int tag) {
if(tag) return (p1 - u) * (v - u) <= 0 && (p2 - u) * (v - u) < 0;
else return (p1 - u) * (v - u) <= 0 && (p2 - u) * (v - u) <= 0;
}
int seg_inter_seg(Pnt a, Pnt b, Pnt c, Pnt d) {
int s1, s2, s3, s4;
int d1, d2, d3, d4;
d1 = (s1 = (b - a) * (c - a));
d2 = (s2 = (b - a) * (d - a));
d3 = (s3 = (d - c) * (a - c));
d4 = (s4 = (d - c) * (b - c));
if((d1 ^ d2) == -2 && (d3 ^ d4) == -2) {
return 1;
}
if(d1 == 0 && ((a - c) ^ (b - c)) <= 0) {
return 2;
}
if(d2 == 0 && ((a - d) ^ (b - d)) <= 0) {
return 2;
}
if(d3 == 0 && ((c - a) ^ (d - a)) <= 0) {
return 2;
}
if(d4 == 0 && ((c - b) ^ (d - b)) <= 0) {
return 2;
}
return 0;
}
int gao(Pnt tp[], int n, Pnt pt[], int m, int tag) {
int mp[505], nxt[505];
memset(mp, -1, sizeof(mp));
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(judge(tp[i], pt[j], pt[(j - 1 + m) % m], pt[j + 1], tag)) {
mp[i] = j;
}
}
}
for(int i = 0; i < n; ++i) {
nxt[i] = -1;
Pnt u = tp[i], v = pt[mp[i]];
for(int j = 0; j < n; ++j) if(i != j) {
if((tp[j] - u) * (v - u) >= 0) {
if(nxt[i] == -1) {
nxt[i] = j;
} else {
int k1 = mp[j], k2 = mp[nxt[i]];
if(k1 < mp[i]) k1 += m;
if(k2 < mp[i]) k2 += m;
if(k1 >= k2) nxt[i] = j;
}
}
}
if(nxt[i] == -1) while(true);
}
int ans = 111111;
for(int i = 0; i < n; ++i) {
int cnt = 1, now = i;
int num = 1;
while(true) {
num += (m + mp[nxt[now]] - mp[now]) % m;
now = nxt[now], ++cnt;
if(!tag) {
if(num >= m && num >= 3) {
if(!seg_inter_seg(tp[i], tp[now], pt[0], pt[1])) break;
}
} else if(num >= m) break;
}
ans = min(ans, cnt);
}
return ans;
}
int update(Pnt tp[], int n, Pnt pt[], int m) {
int M = 0;
for(int i = 0; i < m; ++i) {
if(pnt_in_ploy(tp, n, pt[i]) != 1) res[M ++] = pt[i];
}
for(int i = 0; i < M; ++i) q[i] = res[i];
q[M] = q[0];
return M;
}
int main() {
int n, m, M;
while(cin >> n) {
for(int i = 0; i < n; ++i) p[i].input();
n = graham(p, n, res);
for(int i = 0; i < n; ++i) p[i] = res[i];
p[n] = p[0];
cin >> m;
M = m;
for(int i = 0; i < m; ++i) q[i].input();
m = graham(q, m, res);
for(int i = 0; i < m; ++i) q[i] = res[i];
q[m] = q[0];
if(n == 1) {
if(m == 1) {
if(p[0] == q[0]) cout << M - 1 << endl;
else cout << "ToT" << endl;
} else if(m == 2) {
if(pnt_on_seg(p[0], q[0], q[1])) cout << M - 2 << endl;
else if(p[0] == q[0] || p[0] == q[1]) cout << M - 1 << endl;
else cout << "ToT" << endl;
} else {
int k = pnt_in_ploy(q, m, p[0]);
if(k == 0) cout << M - 2 << endl;
else if(k == 1) cout << M - 3 << endl;
else if(k == 2) cout << M - 1 << endl;
else cout << "ToT" << endl;
}
} else if(n == 2) {
if(m == 1) {
cout << "ToT" << endl;
} else if(m == 2) {
if(pnt_on_seg(p[0], q[0], q[1]) && pnt_on_seg(p[1], q[0], q[1]))
cout << M - 2 << endl;
else cout << "ToT" << endl;
} else {
int k1 = pnt_in_ploy(q, m, p[0]);
int k2 = pnt_in_ploy(q, m, p[1]);
if(k1 < 0 || k2 < 0) cout << "ToT" << endl;
else cout << M - gao(q, m, p, n, 0) << endl;
}
} else {
if(m <= 2) {
cout << "ToT" << endl;
} else if(!check(p, n, q, m)) {
cout << "ToT" << endl;
} else {
m = update(p, n, q, m);
cout << M - gao(q, m, p, n, 1) << endl;
}
}
}
return 0;
}