题意:平面坐标系中有一堆白点与黑点,告诉你他们的坐标,然后让你把他们连接起来,每个白点恰好连接一个黑点。线段不能相交。最后输出每个白点匹配的黑点的序号。
思路:构造二分图每个白点对应一个x结点,黑点对应一个y结点权值是两者的欧氏距离相反数。之后最佳完全匹配就是解,原因是若存在(a,b)(c,d)两个匹配是相交的,那么必定存在(a,c)(b,d)比原来权值更大且不相交。
代码如下:
1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao/ 4 * Last modified : 2014-02-20 20:29 5 * Filename : uva_1411.cpp 6 * Description : 7 * ************************************************/ 8 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <cstdlib> 13 #include <cmath> 14 #include <algorithm> 15 #include <queue> 16 #include <stack> 17 #include <vector> 18 #include <set> 19 #include <map> 20 #define MP(a, b) make_pair(a, b) 21 #define PB(a) push_back(a) 22 #define PF(a) ((a)*(a)) 23 24 using namespace std; 25 typedef long long ll; 26 typedef pair<int, int> pii; 27 typedef pair<unsigned int,unsigned int> puu; 28 typedef pair<int, double> pid; 29 typedef pair<ll, int> pli; 30 typedef pair<int, ll> pil; 31 32 const double INF = 1e30; 33 const double eps = 1E-6; 34 const int LEN = 1010; 35 double g[LEN][LEN], lx[LEN], ly[LEN], slack[LEN]; 36 int linker[LEN], visx[LEN], visy[LEN], tlinker[LEN]; 37 int nx, ny; 38 struct P {double x, y;}; 39 P white[LEN], black[LEN]; 40 41 double dis(P c, P d){return sqrt(PF(c.x - d.x) + PF(c.y - d.y));} 42 43 bool DFS(int x) 44 { 45 visx[x] = 1; 46 for(int y = 0; y < ny; y++) 47 { 48 if(visy[y])continue; 49 double tmp = lx[x] + ly[y] - g[x][y]; 50 if(fabs(tmp) < eps) 51 { 52 visy[y] = 1; 53 if(linker[y] == -1 || DFS(linker[y])) 54 { 55 linker[y] = x; 56 tlinker[x] = y; 57 return true; 58 } 59 } 60 else if(slack[y] > tmp) 61 slack[y] = tmp; 62 } 63 return false; 64 } 65 double KM() 66 { 67 memset(linker,-1,sizeof(linker)); 68 memset(ly,0,sizeof(ly)); 69 for(int i = 0;i < nx;i++) 70 { 71 lx[i] = -INF; 72 for(int j = 0;j < ny;j++) 73 if(g[i][j] > lx[i]) 74 lx[i] = g[i][j]; 75 } 76 for(int x = 0;x < nx;x++) 77 { 78 for(int i = 0;i < ny;i++) 79 slack[i] = INF; 80 while(1) 81 { 82 memset(visx,0,sizeof(visx)); 83 memset(visy,0,sizeof(visy)); 84 if(DFS(x))break; 85 double d = INF; 86 for(int i = 0;i < ny;i++) 87 if(!visy[i] && d > slack[i]) 88 d = slack[i]; 89 for(int i = 0;i < nx;i++) 90 if(visx[i]) 91 lx[i] -= d; 92 for(int i = 0;i < ny;i++) 93 { 94 if(visy[i])ly[i] += d; 95 else slack[i] -= d; 96 } 97 } 98 } 99 double res = 0; 100 for(int i = 0;i < ny;i++) 101 if(linker[i] != -1) 102 res += g[linker[i]][i]; 103 return res; 104 } 105 106 107 int main() 108 { 109 // freopen("in.txt", "r", stdin); 110 111 int n, kase = 1; 112 while(scanf("%d", &n)!=EOF){ 113 if(kase != 1) printf(" "); 114 kase ++; 115 nx = ny = n; 116 for(int i=0; i<n; i++) 117 scanf("%lf%lf", &white[i].x, &white[i].y); 118 for(int i=0; i<n; i++) 119 scanf("%lf%lf", &black[i].x, &black[i].y); 120 for(int i=0; i<n; i++) 121 for(int j=0; j<n; j++) 122 g[j][i] = -dis(white[i], black[j]); 123 KM(); 124 for(int i=0; i<n; i++){ 125 printf("%d ", linker[i]+1); 126 } 127 } 128 return 0; 129 }