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 }

 

 

你可能感兴趣的:(poj)