紫书 第8章 UVa1411 Ants 巨人与鬼

来源:互联网 发布:mac有哪些好玩的游戏 编辑:程序博客网 时间:2024/05/03 20:08

题意:给出平面上n个白点n个黑点,要求两两配对,且配对所连线段没有交点。
解题方法:
由于只需要一种配对方法,从直观上来说本题一定是有解的。由于每一个巨人和鬼都需
要找一个目标,不妨先给“最特殊”的巨人或鬼寻找“搭档”。
考虑y坐标最小的点(即最低点)。如果有多个这样的点,考虑最左边的点(即其中最
左边的点),则所有点的极角在范围[0,π)内。不妨设它是一个巨人,然后把所有其他点按照
极角从小到大的顺序排序后依次检查。
情况1:第一个点是鬼,那么配对完成,剩下的巨人和鬼仍然是一样多,而且不会和这
一条线段交叉,如图8-6(a)所示。
情况2:第一个点是巨人,那么继续检查,直到已检查的点中鬼和巨人一样多为止。找
到了这个“鬼和巨人”配对区间后,只需要把此区间内的点配对,再把区域外的点配对即可,
如图8-6(b)所示。这个配对过程是递归的,好比棋盘覆盖中一样。会不会找不到这样的配
对区间呢?不会的。因为检查完第一个点后鬼少一个,而检查完最后一个点时鬼多一个,而
巨人和鬼的数量差每次只能改变1,因此“从少到多”的过程中一定会有“一样多”的时候。

代码如下:

#include <bits/stdc++.h>using namespace std;const int N = 110;int n;struct Point{    int x, y;    Point(){}    Point(int x, int y) : x(x), y(y){}    double angle(const Point &p) const{        return atan2(y - p.y, x - p.x);    }    bool operator < (const Point &rhs) const{        return y < rhs.y || (y == rhs.y && x < rhs.x);    }    void read(){        scanf("%d%d", &x, &y);    }};struct Node{    Point p;    int id;    double ang;    bool operator <(const Node &rhs) const{        return ang < rhs.ang;    }    void getangle(const Point &p0){        ang = p.angle(p0);    }    int type() const{        return id <= n ? 1 : -1;    }}p[N * 2];int ans[N * 2];void solve(int l, int r){    if(l > r) return ;    int pos = l;    for(int i = l + 1; i <= r; i++){        if(p[i].p < p[pos].p){            pos = i;        }    }    swap(p[pos], p[l]);    int cnt = p[l].type();    for(int i = l + 1; i <= r; i++){        p[i].getangle(p[l].p);    }    sort(p + l + 1, p + r + 1);    for(int i = l + 1; i <= r; i++){        cnt += p[i].type();        if(cnt == 0){            ans[p[l].id] = p[i].id;            ans[p[i].id] = p[l].id;            solve(l + 1, i - 1);            solve(i + 1, r);            return ;        }    }}int main(){    while(scanf("%d", &n) != EOF)    {        memset(ans, 0, sizeof(ans));        for(int i = 1; i <= 2 * n; i++){            p[i].p.read();            p[i].id = i;        }        solve(1, n * 2);        for(int i = 1; i <= n; i++){            printf("%d\n", ans[i] - n);        }    }    return 0;}
0 0
原创粉丝点击