poj 2195 KM算法

n个人要回到n个屋子,要求最小的花费。

KM算法可以求二分图最大权匹配,求最少花费可以先对距离取负数,求最大,再取负数即可。

ps:km算法看的还不是很懂啊《《《》》

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 #define MAXN 110
  9 #define inf 999999999
 10 
 11 struct point
 12 {
 13     int x,y;
 14 }pos_k[MAXN],pos_h[MAXN];
 15 int n,m;
 16 int w[MAXN][MAXN];
 17 int lx[MAXN],ly[MAXN];
 18 int linky[MAXN];
 19 int visx[MAXN],visy[MAXN];
 20 int slack[MAXN];
 21 int nx,ny;
 22 
 23 bool find(int x)
 24 {
 25     visx[x] = true;
 26     for(int y = 1; y <=ny; y++)
 27     {
 28         if(visy[y])
 29             continue;
 30         int t = lx[x] + ly[y] - w[x][y];
 31         if(t==0)
 32         {
 33             visy[y] = true;
 34             if(linky[y]==-1 || find(linky[y]))
 35             {
 36                 linky[y] = x;
 37                 return true;        //找到增广轨
 38             }
 39         }
 40         else if(slack[y] > t)
 41             slack[y] = t;
 42     }
 43     return false;                   //没有找到增广轨(说明顶点x没有对应的匹配,与完备匹配(相等子图的完备匹配)不符)
 44 }
 45 
 46 int KM()                //返回最优匹配的值
 47 {
 48     int i,j;
 49     memset(linky,-1,sizeof(linky));
 50     memset(ly,0,sizeof(ly));
 51     for(i = 1; i <=nx; i++)
 52     {
 53         lx[i] = -inf;
 54          for(j = 1; j <=nx; j++)
 55             if(w[i][j] > lx[i])
 56                 lx[i] = w[i][j];
 57     }
 58 
 59     for(int x = 1; x <=nx; x++)
 60     {
 61         for(i = 1; i <=nx; i++)
 62             slack[i] = inf;
 63         while(true)
 64         {
 65             memset(visx,0,sizeof(visx));
 66             memset(visy,0,sizeof(visy));
 67             if(find(x))                     //找到增广轨,退出
 68                 break;
 69             int d = inf;
 70             for(i = 1; i <=nx; i++)          //没找到,对l做调整(这会增加相等子图的边),重新找
 71             {
 72                 if(!visy[i] && d > slack[i])
 73                     d = slack[i];
 74             }
 75             for(i = 1; i <=nx; i++)
 76             {
 77                 if(visx[i])
 78                     lx[i] -= d;
 79             }
 80             for(i = 1; i <=ny; i++)
 81             {
 82                 if(visy[i])
 83                      ly[i] += d;
 84                 else
 85                     slack[i] -= d;
 86             }
 87         }
 88     }
 89     int result = 0;
 90     for(i = 1; i <=ny; i++)
 91     if(linky[i]>-1)
 92         result += w[linky[i]][i];
 93     return result;
 94 }
 95 
 96 int dist(point a,point b)
 97 {
 98     int dis=0;
 99     dis+=(a.x-b.x)>0?(a.x-b.x):(b.x-a.x);
100     dis+=(a.y-b.y)>0?(a.y-b.y):(b.y-a.y);
101     return dis;
102 }
103 
104 bool read()
105 {
106     scanf("%d%d",&n,&m);
107     getchar();
108     char buf[MAXN];
109     if(n+m==0)
110         return false;
111     nx=0,ny=0;
112     for(int i=1;i<=n;i++)
113     {
114         gets(buf);
115         for(int j=0;j<m;j++)
116         {
117             if(buf[j]=='H')
118             {
119                 pos_h[ny].x=i;
120                 pos_h[ny++].y=j+1;
121             }
122             else if(buf[j]=='m')
123             {
124                 pos_k[nx].x=i;
125                 pos_k[nx++].y=j+1;
126             }
127         }
128     }
129     for(int i=0;i<nx;i++)
130         for(int j=0;j<ny;j++)
131         {
132             w[i+1][j+1]=-dist(pos_k[i],pos_h[j]);//取负
133         }
134     return true;
135 }
136 
137 int main()
138 {
139     while(read())
140     {
141         printf("%d\n",-KM());
142     }
143     return 0;
144 }

 

 

posted @ 2012-09-27 14:29  Missa  阅读(399)  评论(0编辑  收藏  举报