您的位置:首页 > 其它

UVaLive4043 UVa1411 Ants 巨人与鬼

2016-02-18 09:34 106 查看
题意:给出平面上n个白点n个黑点,要求两两配对,且配对所连线段没有交点。

法一:暴力

随机一个初始方案,枚举任意两条线段如果有交点就改一下。

效率其实挺好的。

法二:二分图最佳完美匹配

显然没有交点的方案是所有线段的长度和最小的方案,将边权构造为欧几里德距离即可,$O(n^4)$的算法效率远不及法一,$O(n^3)$与法一持平。

法三:分治

这是紫书上介绍的方法,每次找出一个最下最左的点,将其他的点相对于这个点进行极角排序,按极角序扫描,当白点和黑点一样多时(算上最下最左那个点),将第一个点和最后一个点配对,递归处理剩下的两部分。时间复杂度大概是$O(n^2\log{n})$的?效率最高。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>

using namespace std;
const int N = 100 + 10;

#include<cmath>
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);
}
};

int n;
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) {
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) == 1) {
for(int i = 1; i <= (n << 1); i++) {
p[i].p.read();
p[i].id = i;
}

solve(1, n << 1);
for(int i = 1; i <= n; i++) {
printf("%d\n", ans[i] - n);
}
}

return 0;
}


分治算法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: