POJ 2195 【二分图最佳匹配】.cpp

题意:

有 n 个房子和 n 个人

每个人走一个单元你就要付 1$

有什么办法可以让把所有人都分派到房子里 而花费最少

 

输入:

  给出n m 表示该矩阵由n 行 m 列组成

  然后给出一个n*m的图

  . 表示空地 H 表示房子 m 表示人

思路:

二分图最佳匹配<有权还要完全匹配>

Tips:

建图很有趣~

Code:

 

View Code
  1 #include <stdio.h>
  2 #include <cstring>
  3 #include <cmath>
  4 #define M 110
  5 #define inf 0x1f1f1f1f
  6 
  7 struct Node
  8 {
  9     int x;
 10     int y;
 11 }man[110], home[110];
 12 
 13 int n,nx,ny;
 14 int link[M],lx[M],ly[M],slack[M];    //lx,ly为顶标,nx,nx分别为x点集y点集的个数
 15 int visx[M],visy[M],w[M][M];
 16 
 17 int DFS(int x)
 18 {
 19     visx[x] = 1;
 20     for (int y = 1;y <= nx;y ++)
 21     {
 22         if (visy[y])
 23             continue;
 24         int t = lx[x] + ly[y] - w[x][y];
 25         if (t == 0)       //
 26         {
 27             visy[y] = 1;
 28             if (link[y] == -1||DFS(link[y]))
 29             {
 30                 link[y] = x;
 31                 return 1;
 32             }
 33         }
 34         else if (slack[y] > t)  //不在相等子图中slack 取最小的
 35             slack[y] = t;
 36     }
 37     return 0;
 38 }
 39 int KM()
 40 {
 41     int i,j;
 42     memset (link,-1,sizeof(link));
 43     memset (ly,0,sizeof(ly));
 44     for (i = 1;i <= nx;i ++)            //lx初始化为与它关联边中最大的
 45         for (j = 1,lx[i] = -inf;j <= nx;j ++)
 46             if (w[i][j] > lx[i])
 47                 lx[i] = w[i][j];
 48 
 49     for (int x = 1;x <= nx;x ++)
 50     {
 51         for (i = 1;i <= nx;i ++)
 52             slack[i] = inf;
 53         while (1)
 54         {
 55             memset (visx,0,sizeof(visx));
 56             memset (visy,0,sizeof(visy));
 57             if (DFS(x))     //若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
 58                 break;  //若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
 59                         //方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
 60                         //所有在增广轨中的Y方点的标号全部加上一个常数d
 61             int d = inf;
 62             for (i = 1;i <= nx;i ++)
 63                 if (!visy[i]&&d > slack[i])
 64                     d = slack[i];
 65             for (i = 1;i <= nx;i ++)
 66                 if (visx[i])
 67                     lx[i] -= d;
 68             for (i = 1;i <= nx;i ++)  //修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
 69                 if (visy[i])
 70                     ly[i] += d;
 71                 else
 72                     slack[i] -= d;
 73         }
 74     }
 75     int res = 0;
 76     for (i = 1;i <= nx;i ++)
 77         if (link[i] > -1)
 78             res += w[link[i]][i];
 79     return -res;
 80 }
 81 
 82 int main ()
 83 {
 84     int i, j, k;
 85     int m;
 86     char G[110][110];
 87     while (scanf("%d %d", &n, &m)!=EOF)
 88     {
 89         if(n == 0 && m == 0) break;
 90         nx = 1, ny = 1;
 91       //  memset (w,0,sizeof(w));
 92       getchar();
 93       for(i = 0; i < n; ++i)
 94         gets(G[i]);
 95 
 96       for(i = 0; i < n; ++i)
 97       for(j = 0; j < m; ++j) {
 98         if(G[i][j] == 'm') {
 99             man[nx].x = i;
100             man[nx++].y = j;
101         }
102         else if(G[i][j] == 'H') {
103             home[ny].x = i;
104             home[ny++].y = j;
105         }
106       }
107 
108       for(i = 1; i < nx; ++i)
109       for(j = 1; j < ny; ++j) {
110         w[i][j] = -fabs(man[i].x - home[j].x) - fabs(man[i].y - home[j].y);
111       }
112 
113         nx--;
114         int ans = KM();
115         printf ("%d\n",ans);
116     }
117     return 0;
118 }

 

 

题目链接:http://poj.org/problem?id=2195

posted @ 2012-09-28 08:06  Griselda.  阅读(204)  评论(0编辑  收藏  举报