CF1045E
题意
给定平面上 \(n\) 个点,有黑白两种颜色。
问一种连点方案使得黑色和白色分别联通,并且连边无交点。
\(1\ \leq\ n\ \leq\ 1000,\ 0\ \leq\ x,\ y\ \leq\ 10^4\)
做法1
考虑一种特殊情况:所给点集的凸包为三角形,三个顶点为 \(a,\ b,\ c\),并且有个顶点 \(c\) 颜色不同。
如果三角形内部无点直接返回。
如果三角形内部存在一个点 \(d\) 使得 \(c,\ d\) 同色,则可以考虑剖分成 \((a,\ b,\ d),\ (c,\ d,\ a),\ (c,\ d,\ b)\) 三个子问题。
否则直接与 \(a\) 连边即可。
现在考虑一般情况即凸包不是三角形。
如果凸包上的点存在黑白交替的情况,即存在 \(\geq\ 3\) 条边两端点颜色不同可以证明无解。
如果均为一种颜色,找到点集中一个异色的点 \(p\)。考虑凸包上相邻的两个点 \(a,\ b\),逐个做子问题 \((a,\ b,\ p)\) 即可。
否则设凸包上的点为 \(b_1,\ b_2,\ ...,\ b_p,\ w_1,\ w_2,\ ...,\ w_q\),依次处理 \((b_1,\ b_2,\ w_1),\ (b_2,\ b_3,\ w_1),\ ...,\ (b_{p\ -\ 1},\ b_p,\ w_1),\ (w_1,\ w_2,\ b_1),\ (w_2,\ w_3,\ b_1),\ ...,\ (w_{q\ -\ 1},\ w_q,\ b_1)\)。
代码
#include <bits/stdc++.h>
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
const int maxn = 1e3 + 10;
struct point {
int x, y, c, i;
point() {}
point(int x, int y, int c = 0, int i = 0): x(x), y(y), c(c), i(i) {}
} pnt[maxn];
int det(const point &a, const point &b) { return a.x * b.y - a.y * b.x; }
bool operator == (const point &a, const point &b) { return a.x == b.x && a.y == b.y; }
point operator - (const point &a, const point &b) { return point(a.x - b.x, a.y - b.y); }
bool in_range(const point &o, const point &a, const point &b, const point &c) { return det(a - o, b - o) > 0 && det(b - o, c - o) > 0; }
bool in_triangle(const point &p, const point &a, const point &b, const point &c) {
if(p == a || p == b || p == c) return 0;
if(det(c - a, b - a) > 0) return in_triangle(p, a, c, b);
return in_range(a, b, p, c) && in_range(b, c, p, a) && in_range(c, a, p, b);
}
bool all_same;
int n, m, diff, hull[maxn << 1];
vector<pair<int, int> > ans;
void solve(const vector<point> &all, const point &a, const point &b, const point &c) {
if(!all.size()) return;
for (const auto &t: all) if(t.c == c.c) {
vector<point> x, y, z;
for (const auto &s: all) {
if(in_triangle(s, a, b, t)) x.push_back(s);
if(in_triangle(s, b, c, t)) y.push_back(s);
if(in_triangle(s, a, c, t)) z.push_back(s);
}
solve(x, a, b, t);
solve(y, c, t, b);
solve(z, c, t, a);
ans.push_back(make_pair(t.i, c.i));
return;
}
for (const auto &t: all) ans.push_back(make_pair(t.i, a.i));
return;
}
int main() {
scanf("%d", &n);
all_same = 1;
for (int i = 1; i <= n; ++i) {
int x, y, c;
scanf("%d%d%d", &x, &y, &c);
pnt[i] = point(x, y, c, i - 1);
all_same &= (c == pnt[1].c);
}
sort(pnt + 1, pnt + n + 1, [&](point a, point b) { return a.x == b.x ? a.y < b.y : a.x < b.x; });
if(all_same) {
printf("%d\n", n - 1);
for (int i = 1; i < n; ++i) printf("%d %d\n", pnt[i].i, pnt[i + 1].i);
return 0;
}
for (int i = 1; i <= n; ++i) {
while(m > 1 && det(pnt[hull[m]] - pnt[hull[m - 1]], pnt[i] - pnt[hull[m - 1]]) > 0) --m;
hull[++m] = i;
}
for (int rem = m, i = n - 1; i; --i) {
while(m > rem && det(pnt[hull[m]] - pnt[hull[m - 1]], pnt[i] - pnt[hull[m - 1]]) > 0) --m;
hull[++m] = i;
}
--m;
for (int i = 1; i <= m; ++i) hull[i + m] = hull[i];
for (int i = 1; i <= m; ++i) if(pnt[hull[i]].c != pnt[hull[i + 1]].c) {
for (int j = 1; j <= m; ++j) hull[j] = hull[j + i];
break;
}
#ifdef DEBUG
for (int i = 1; i <= m; ++i) printf("(%d, %d) %d\n", pnt[hull[i]].x, pnt[hull[i]].y, pnt[hull[i]].c);
#endif
for (int i = 1; i <= m; ++i) {
if(pnt[hull[i]].c != pnt[hull[i + 1]].c) ++diff;
if(diff > 1) { puts("Impossible"); return 0; }
}
if(!diff) {
for (int pivot = 1; pivot <= n; ++pivot) if(pnt[pivot].c != pnt[hull[1]].c) {
bool flag = 1;
for (int i = 1; i <= m; ++i) if(hull[i] == pivot) { flag = 0; break; }
if(flag) {
for (int i = 1; i <= m; ++i) {
point a = pnt[hull[i]], b = pnt[hull[i + 1]], c = pnt[pivot];
vector<point> all;
for (int j = 1; j <= n; ++j) if(in_triangle(pnt[j], a, b, c)) all.push_back(pnt[j]);
solve(all, a, b, c);
if(i < m) ans.push_back(make_pair(a.i, b.i));
}
break;
}
}
}
else {
for (int pivot = 1; pivot <= m; ++pivot) if(pnt[hull[pivot]].c != pnt[hull[1]].c) {
for (int i = 1; i < pivot - 1; ++i) {
point a = pnt[hull[i]], b = pnt[hull[i + 1]], c = pnt[hull[pivot]];
vector<point> all;
for (int j = 1; j <= n; ++j) if(in_triangle(pnt[j], a, b, c)) all.push_back(pnt[j]);
solve(all, a, b, c);
ans.push_back(make_pair(a.i, b.i));
}
for (int i = pivot; i < m; ++i) {
point a = pnt[hull[i]], b = pnt[hull[i + 1]], c = pnt[hull[1]];
vector<point> all;
for (int j = 1; j <= n; ++j) if(in_triangle(pnt[j], a, b, c)) all.push_back(pnt[j]);
solve(all, a, b, c);
ans.push_back(make_pair(a.i, b.i));
}
break;
}
}
printf("%d\n", ans.size());
for (auto t: ans) printf("%d %d\n", t.first, t.second);
return 0;
}