uva 1411(二分图最大权匹配)

题意:平面坐标系中有一堆白点与黑点,告诉你他们的坐标,然后让你把他们连接起来,每个白点恰好连接一个黑点。线段不能相交。最后输出每个白点匹配的黑点的序号。

思路:构造二分图每个白点对应一个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 }
View Code
奔跑吧!少年!趁着你还年轻
原文地址:https://www.cnblogs.com/shu-xiaohao/p/3577150.html