题意:
一个平面上有n个黑色的点,n个白色的点,要求黑色的点与白色点之间一一配对,且线段之间不相交。
思路:
线段不相交并不好处理,想了很久想不出,所以看了蓝书的讲解。
一个很明显的结论是,不相交的线段一定比相交的线段短,如图:一个较为直观的例子。
由于点之间一一对应,所以肯定用二分图匹配,然后要使得所有线段之和最短,那么就是求一个带权最小匹配,上KM算法解决。
把所有的边权取负值,求最大匹配即可。
代码:
1 #include <stdio.h> 2 #include <math.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int N = 105; 9 10 double mp[N][N]; 11 12 struct node 13 { 14 double x,y; 15 node(double a,double b) 16 { 17 x = a; 18 y = b; 19 } 20 }; 21 22 vector<node> nx,ny; 23 24 bool vis_x[N],vis_y[N]; 25 int match[N]; 26 double lx[N],ly[N]; 27 double slack[N]; 28 int ma[N]; 29 30 double cal(int i,int j) 31 { 32 double dx = pow(nx[i].x - ny[j].x,2); 33 double dy = pow(nx[i].y - ny[j].y,2); 34 35 return sqrt(dx + dy); 36 } 37 38 bool dfs(int u,int n) 39 { 40 vis_x[u] = 1; 41 42 for (int i = 0;i < n;i++) 43 { 44 if (vis_y[i]) continue; 45 46 double gap = lx[u] + ly[i] - mp[u][i]; 47 48 //getchar(); 49 50 //printf("%.6f %.6f %.6f %.6f ",lx[u],ly[i],mp[u][i],gap); 51 52 if (fabs(gap) < 1e-6) 53 { 54 vis_y[i] = 1; 55 56 if (match[i] == -1 || dfs(match[i],n)) 57 { 58 match[i] = u; 59 return true; 60 } 61 } 62 else 63 { 64 slack[i] = min(slack[i],gap); 65 } 66 } 67 68 return false; 69 } 70 71 void km(int n) 72 { 73 memset(ly,0,sizeof(ly)); 74 memset(match,-1,sizeof(match)); 75 76 for (int i = 0;i < n;i++) 77 { 78 lx[i] = mp[i][0]; 79 80 for (int j = 1;j < n;j++) 81 { 82 lx[i] = max(lx[i],mp[i][j]); 83 } 84 } 85 86 for (int i = 0;i < n;i++) 87 { 88 for (int j = 0;j < n;j++) slack[j] = 1e15; 89 //printf("gg"); 90 while (1) 91 { 92 //printf("233"); 93 memset(vis_x,0,sizeof(vis_x)); 94 memset(vis_y,0,sizeof(vis_y)); 95 96 if (dfs(i,n)) break; 97 98 double d = 1e15; 99 100 for (int j = 0;j < n;j++) 101 { 102 if (!vis_y[j]) d = min(slack[j],d); 103 } 104 105 for (int j = 0;j < n;j++) 106 { 107 if (vis_x[j]) lx[j] -= d; 108 109 if (vis_y[j]) ly[j] += d; 110 } 111 112 //getchar(); 113 114 //printf("%.6f ** ",d); 115 } 116 } 117 } 118 119 int main() 120 { 121 int n; 122 int kase = 0; 123 124 while (scanf("%d",&n) != EOF) 125 { 126 if (kase++) printf(" "); 127 128 nx.clear(); 129 ny.clear(); 130 131 for (int i = 0;i < n;i++) 132 { 133 double x,y; 134 scanf("%lf%lf",&x,&y); 135 136 nx.push_back(node(x,y)); 137 } 138 139 for (int i = 0;i < n;i++) 140 { 141 double x,y; 142 scanf("%lf%lf",&x,&y); 143 144 ny.push_back(node(x,y)); 145 } 146 147 for (int i = 0;i < n;i++) 148 { 149 for (int j = 0;j < n;j++) 150 { 151 mp[i][j] = -cal(i,j); 152 } 153 } 154 155 km(n); 156 157 for (int i = 0;i < n;i++) 158 { 159 int a = i + 1,b = match[i] + 1; 160 ma[b] = a; 161 } 162 163 for (int i = 0;i < n;i++) 164 { 165 printf("%d ",ma[i+1]); 166 } 167 } 168 169 return 0; 170 }