题目概述
平面中有白点和黑点各N个,各编号1到N,给定他们的坐标x,y,问如何连接黑点与白点使得所有连线互不相交
任何三点不共线,不存在重合点
时限
5000ms/15000ms
输入
第一行正整数N,其后N行,每行两个整数x,y,描述白点坐标,其后N行,每行两个整数x,y,描述黑点坐标,输入到EOF为止
限制
1<=N<=100;-10000<=x,y<=10000
输出
每组数据输出在N行中,每行一个数,为与白点匹配的黑点序号,按白点序号升序排列,答案可能有多种,输出任意一组均可
样例输入
5
-42 58
44 86
7 28
99 34
-13 -59
-47 -44
86 74
68 -75
-68 60
99 -60
样例输出
4
2
1
5
3
讨论
计算几何?额是这么想的,借用一点冒泡排序的思想,但几乎就是暴力解决,思想就是,只要相交,就交换,直到所有线都不相交为止
为了对抗暴力,采用了一点极端写法,其实是不值得提倡的,不过也算杀入排行第一页了
这个题正确解法应该是用km算法吧,二分图一直没动,暂时也写不了
题解状态
164K,16MS,C++,1350B
题解代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 102
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-8
short N;//每种点总数 不超过100
short x[MAXN], y[MAXN], x2[MAXN], y2[MAXN], match[MAXN];//白点和黑点的坐标 及其匹配关系 坐标绝对值不超过10000 匹配关系不超过100
inline int xp(int x1, int y1, int x2, int y2, int x3, int y3)//向量积 可能上溢 都用int
{
return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2);
}
inline bool intersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)//相交 这两个函数需要频繁调用 都是内联
{
int xp1 = xp(x3, y3, x1, y1, x2, y2), xp2 = xp(x4, y4, x1, y1, x2, y2), xp3 = xp(x1, y1, x3, y3, x4, y4), xp4 = xp(x2, y2, x3, y3, x4, y4);
return(xp1 > 0 && xp2 < 0 || xp1 < 0 && xp2>0) && (xp3>0 && xp4 < 0 || xp3 < 0 && xp4>0);//按题目要求只有内交 省去了后面的判断 同时为了提速 直接以符号判断异号而非从前按积的符号判断
}
void fun()
{
for (int p = 0; p < N; p++)
scanf("%d%d", &x[p], &y[p]);//input
for (int p = 0; p < N; p++) {
scanf("%d%d", &x2[p], &y2[p]);//input
match[p] = p;//顺手初始化匹配
}
bool f = 1;//flag 表示存在相交
while (f) {
f = 0;//初始化为没有相交
for (int p = 0; p < N; p++)
for (int i = p + 1; i < N; i++)
if (intersect(x[p], y[p], x2[match[p]], y2[match[p]], x[i], y[i], x2[match[i]], y2[match[i]])) {
f = 1;
match[p] ^= match[i];//为了提速而没用swap函数 用了这个老办法
match[i] ^= match[p];
match[p] ^= match[i];
}
}
for (int p = 0; p < N; p++)
printf("%d\n", match[p] + 1);//output
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);
while (~scanf("%d", &N))//input
fun();
}
EOF