//目录

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 }
View Code

 

posted @ 2017-05-01 21:37  小草的大树梦  阅读(282)  评论(0编辑  收藏  举报