[分治] UVa1411 Ants 巨人与鬼 (分治之终极运用)

题目

给定一些黑点白点,要求一个黑点连接一个白点,并且所有线段都不相交

思路

LRJ强强强,网上一堆各种什么二分图匹配的算法,LRJ大佬一个分治 O ( n 2 l o g n ) 强破。


首先,先找一个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;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80561614