题目
给定一些黑点白点,要求一个黑点连接一个白点,并且所有线段都不相交
思路
LRJ强强强,网上一堆各种什么二分图匹配的算法,LRJ大佬一个分治
强破。
首先,先找一个y坐标最小的点(y同时最小时,再选x最小),随后以这个点为中心进行极角排序,排序后的第一个角:
- 如果与基准点颜色不同,直接匹配。然后处理剩余。
- 如果与基准点颜色不同,进行计数。与基准点颜色相同cnt++,颜色不同cnt–。当cnt=0时,分治为计数区域内和(基准点和其它点)。
一直递归,重新递归后,在重新执行。
必然可以递归完。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 200 + 10;
int n, ans[maxn];
struct node {
int x, y, k, color;
double rad;
bool operator < (const struct node &rhs) const {
return rad < rhs.rad;
}
}A[maxn], temp[maxn];
void solve(int L, int R) {
if (L == R - 2) { //递归终止,仅有两个元素
if (A[L].color == 1) {
ans[A[L].k] = A[R - 1].k;
} else
ans[A[R - 1].k] = A[L].k;
return;
}
int minp = L;
for (int i = L; i < R; i++)
if (A[i].y < A[minp].y || (A[i].y == A[minp].y && A[i].x < A[minp].x))
minp = i;
swap(A[L], A[minp]);
for (int i = L + 1; i < R; i++) {
int nx = A[i].x - A[L].x;
int ny = A[i].y - A[L].y;
A[i].rad = atan2(ny, nx);
}
sort(A+L+1,A+R);
if (A[L].color == A[L + 1].color) {
int cnt = 0, py = L + 1;
while (cnt != 0 || py == (L + 1)) {
if (A[py].color == A[L].color) cnt++;
else cnt--;
py++;
}
swap(A[L], A[py - 1]);
solve(L, py - 1);
solve(py - 1, R);
}
else {
solve(L, L + 2);
solve(L + 2, R);
}
}
int main() {
while (scanf("%d", &n) == 1 && n) {
int x, y;
for (int i = 0; i < 2*n; i++) {
scanf("%d%d", &x, &y);
A[i].x = x; A[i].y = y; A[i].k = i % n;
if (i < n) A[i].color = 1;
else A[i].color = 0;
}
solve(0, 2 * n);
for (int i = 0; i < n; i++)
printf("%d\n", ans[i]+1);
printf("\n");
}
return 0;
}