紫薯P230
题意:给出平面上n个白点n个黑点,要求两两配对,且配对所连线段没有交点。
紫薯思路:找出y坐标最小的点,如果多个,考虑x最小的。将其他点相对于这个点按极角从小到大排序,然后开始扫描,当白点和黑点一样多时(算上最下面的点),第一个和最后一个匹配,然后递归匹配中间的和外边这两部分
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 #include <cstdio> 6 using namespace std; 7 const int N = 100 + 10; 8 int n; 9 struct Point 10 { 11 int x, y; 12 Point() {} 13 Point(int x, int y) : x(x), y(y) {} 14 double angle(const Point& p) const // 求极角 15 { 16 return atan2(y - p.y, x - p.x); 17 } 18 bool operator< (const Point& p) const // 定义 < 19 { 20 return y < p.y || (y == p.y && x < p.x); 21 } 22 void read() // 读入坐标 23 { 24 scanf("%d%d", &x, &y); 25 } 26 }; 27 struct Node 28 { 29 Point p; // 每一个点包含x,y坐标 30 int id; 31 double ang; // 与标准点的极角 32 bool operator< (const Node& node) const // 定义Node的<,按极角从小到大排序 33 { 34 return ang < node.ang; 35 } 36 void getAngle(const Node& node) 37 { 38 ang = p.angle(node.p); 39 } 40 int type() // 如果是黑点(白点) 返回1,否则返回-1,判断黑点和白点数量相等时使用 41 { 42 return id <= n ? 1 : -1; 43 } 44 }p[N * 2]; 45 int ans[N * 2]; // 配对表 46 void solve(int l, int r) 47 { 48 if (l > r) 49 return; 50 int pos = l; 51 for (int i = l + 1; i <= r; i++) 52 { 53 if (p[i].p < p[pos].p) 54 pos = i; 55 } 56 swap(p[l], p[pos]); // 让怕p[l]成为最下面的点,y最小 57 int cnt = p[l].type(); 58 for (int i = l + 1; i <= r; i++) // 求出所有点与标准的极角大小 59 { 60 p[i].getAngle(p[l]); 61 } 62 sort(p + l + 1, p + r + 1); // 按极角从小到大排序 63 for (int i = l + 1; i <= r; i++) 64 { 65 cnt += p[i].type(); 66 if (!cnt) // 黑点和白点相等时 cnt == 0 67 { 68 ans[ p[i].id ] = p[l].id; // 此时的第一个 和 最后一个配对 69 ans[ p[l].id ] = p[i].id; 70 solve(l + 1, i - 1); // 解决内部的 71 solve(i + 1, r); // 解决外部的 72 return; 73 } 74 } 75 } 76 int main() 77 { 78 while (scanf("%d", &n) != EOF) 79 { 80 for (int i = 1; i <= (n << 1); i++) 81 { 82 p[i].p.read(); 83 p[i].id = i; 84 } 85 solve(1, n << 1); 86 for (int i = 1; i <= n; i++) 87 { 88 printf("%d ", ans[i] - n); 89 } 90 } 91 return 0; 92 }