LA 4043 最优匹配
题目链接:https://vjudge.net/contest/161820#problem/A
题意: n 个 白点,n 个黑点,给出了坐标,求完美匹配后,各点不相交,输出白点对于的黑点编号;(输出输错了 (;´д`)ゞ)
分析:(a1-b1) (a2-b2)
如果这样连接,那么肯定大于 (a1-b2) (a2-b1);也就说,我们要的完美匹配要是权值最小的匹配;
这样,我们的权值,可以全改为负数,这样就可以转为普通的KM算法了;
KM算法(我的理解):
可行标 lx(i) + ly(j)>=w(i,j),当完全子图中的 所有lx(i) + ly(j) ==w(i,j) 时,就有,这个子图是最大权匹配的完美匹配(最佳完美匹配);
怎么得到可行标呢? 初始化话所有X是邻接阵里面最大的那一条,然后在匈牙利树上找,不断的扩充这个匈牙利树,直到成为一个完全子图;
怎么扩充匈牙利树呢? 每次在S,T' 中找最小的一个lx(x) + ly(y) -w(x,y),去修改原来的匈牙利树,使得有可能有新的边加进来;
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define esp 1e-10 5 const double inf = 1e20; 6 const int maxn = 1000; 7 int n; 8 double W[maxn][maxn]; 9 double Lx[maxn],Ly[maxn]; 10 int lefts[maxn]; 11 bool S[maxn],T[maxn]; 12 13 14 bool match(int i) { 15 S[i] = true; 16 for(int j=1;j<=n;j++) 17 { 18 if(fabs(Lx[i]+Ly[j]-W[i][j])<esp&&!T[j]) { 19 T[j] = true; 20 if(!lefts[j]||match(lefts[j])) { 21 lefts[j] = i; 22 return true; 23 } 24 } 25 } 26 return false; 27 } 28 29 void update() { 30 double a = inf; 31 for(int i=1;i<=n;i++) if(S[i]) 32 for(int j=1;j<=n;j++) if(!T[j]) 33 a = min(a,Lx[i]+Ly[j]-W[i][j]); 34 35 for(int i=1;i<=n;i++) { 36 if(S[i]) Lx[i]-=a; 37 if(T[i]) Ly[i]+=a; 38 } 39 } 40 41 void KM() { 42 for(int i=1;i<=n;i++) { 43 lefts[i] =0; 44 Ly[i] = 0; 45 Lx[i] = -inf; 46 for(int j=1;j<=n;j++) { 47 Lx[i] = max(Lx[i],W[i][j]); 48 } 49 } 50 51 for(int i=1;i<=n;i++) { 52 for(;;) { 53 for(int j=1;j<=n;j++) 54 S[j] = T[j] = 0; 55 if(match(i)) 56 break; 57 else update(); 58 } 59 } 60 } 61 62 struct Point { 63 double x,y; 64 }points[maxn]; 65 66 67 int main() 68 { 69 while(scanf("%d",&n)!=EOF) { 70 for(int i=1;i<=2*n;i++) 71 scanf("%lf%lf",&points[i].x,&points[i].y); 72 73 for(int i=1;i<=n;i++) { 74 double x1 = points[i].x; 75 double y1 = points[i].y; 76 77 for(int j=n+1;j<=2*n;j++) { 78 double x2 = points[j].x; 79 double y2 = points[j].y; 80 W[j-n][i] = -sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 81 } 82 } 83 84 KM(); 85 86 for(int i=1;i<=n;i++) 87 printf("%d\n",lefts[i]); 88 89 } 90 return 0; 91 }