2195

1 /*
2 最小权完备匹配
3
4 这题目是 带权二分图的最大/小权问题,可以用hungarian算法的扩展算法Kuhn-Munkres算法来解决
5
6 Kuhn-Munkres算法利用二分图最大匹配的思想来找出最大/小权匹配
7 */
8
9 // include file
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <cmath>
14 #include <cctype>
15 #include <ctime>
16
17 #include <iostream>
18 #include <sstream>
19 #include <fstream>
20 #include <iomanip>
21 #include <bitset>
22 #include <strstream>
23
24 #include <algorithm>
25 #include <string>
26 #include <vector>
27 #include <queue>
28 #include <set>
29 #include <list>
30 #include <functional>
31
32 using namespace std;
33
34 // typedef
35 typedef long long LL;
36 typedef unsigned long long ULL;
37
38 //
39 #define read freopen("in.txt","r",stdin)
40 #define write freopen("out.txt","w",stdout)
41 #define FORi(a,b,c) for(int i=(a);i<(b);i+=c)
42 #define FORj(a,b,c) for(int j=(a);j<(b);j+=c)
43 #define FORk(a,b,c) for(int k=(a);k<(b);k+=c)
44 #define FORp(a,b,c) for(int p=(a);p<(b);p+=c)
45
46 #define FF(i,a) for(int i=0;i<(a);i+++)
47 #define FFD(i,a) for(int i=(a)-1;i>=0;i--)
48 #define Z(a) (a<<1)
49 #define Y(a) (a>>1)
50
51 const double eps = 1e-6;
52 const double INFf = 1e10;
53 const int INFi = 1000000000;
54 const double Pi = acos(-1.0);
55
56 template<class T> inline T sqr(T a){return a*a;}
57 template<class T> inline T TMAX(T x,T y)
58 {
59 if(x>y) return x;
60 return y;
61 }
62 template<class T> inline T TMIN(T x,T y)
63 {
64 if(x<y) return x;
65 return y;
66 }
67 template<class T> inline void SWAP(T &x,T &y)
68 {
69 T t = x;
70 x = y;
71 y = t;
72 }
73 template<class T> inline T MMAX(T x,T y,T z)
74 {
75 return TMAX(TMAX(x,y),z);
76 }
77
78
79 // code begin
80 #define MAXN 110
81 int R,C,N;
82 int cost[MAXN][MAXN];
83 int mt[MAXN];
84 bool S[MAXN];
85 bool T[MAXN];
86 int lx[MAXN];
87 int ly[MAXN];
88
89 struct node
90 {
91 int r;
92 int c;
93 };
94 node X[MAXN];
95 node Y[MAXN];
96 int xs;
97 int ys;
98
99 bool hungarian_MM(int i)
100 {
101 S[i]=true;
102 FORj(0,N,1)
103 {
104 if( !T[j] && lx[i]+ly[j]==cost[i][j])
105 {
106 T[j]=true;
107 if( mt[j]==-1 || hungarian_MM( mt[j] ))
108 {
109 mt[j] = i;
110 return true;
111 }
112 }
113 }
114 return false;
115 }
116
117 int KM_PM(bool flag=true) //true 是求最大权和,false是求最小权和
118 {
119 if(!flag)
120 {
121 FORi(0,N,1)
122 {
123 FORj(0,N,1)
124 {
125 cost[i][j] = -cost[i][j];
126 }
127 }
128 }
129
130 // 初始化顶标
131 FORi(0,N,1)
132 {
133 lx[i] = -INFi;
134 ly[i] = 0;
135 FORj(0,N,1)
136 {
137 lx[i] = TMAX(lx[i],cost[i][j]);
138 }
139 }
140
141 //
142 memset(mt,-1,sizeof(int)*MAXN);
143 FORi(0,N,1)
144 {
145 while(true)
146 {
147 // 对于每一个点都必须找到了增广路径之后才能跳出循环
148 memset(S,0,sizeof(bool)*MAXN);
149 memset(T,0,sizeof(bool)*MAXN);
150 if( hungarian_MM(i))
151 break;
152 // 否则修改标号
153 int d = INFi;
154 FORi(0,N,1)
155 {
156 if( S[i])
157 FORj(0,N,1)
158 {
159 if(!T[j])
160 {
161 d = TMIN(d,lx[i]+ly[j]-cost[i][j]);
162 }
163 }
164 }
165
166 // 对所有的顶点修改顶标
167 FORi(0,N,1)
168 {
169 if(S[i])
170 lx[i] -= d;
171 if(T[i])
172 ly[i] += d;
173 }
174 }
175 }
176
177 //找到了最优匹配了
178 int ans = 0;
179 FORi(0,N,1)
180 {
181 ans += cost[mt[i]][i];
182 }
183 if(!flag)
184 {
185 ans = -ans;
186 FORi(0,N,1)
187 {
188 FORj(0,N,1)
189 {
190 cost[i][j] = -cost[i][j];
191 }
192 }
193 }
194
195 return ans;
196 }
197
198 int main()
199 {
200 read;
201 write;
202 char in[MAXN];
203 while(scanf("%d %d",&R,&C)!=-1)
204 {
205 if(R+C==0) break;
206 xs = 0;
207 ys = 0;
208 FORi(0,R,1)
209 {
210 scanf("%s",in);
211 FORj(0,C,1)
212 {
213 if(in[j]=='H')
214 {
215 X[xs].r = i;
216 X[xs].c = j;
217 xs++;
218 }
219 else if(in[j]=='m')
220 {
221 Y[ys].r = i;
222 Y[ys].c = j;
223 ys++;
224 }
225 }
226 }
227
228 N = xs;
229 FORi(0,N,1)
230 {
231 FORj(0,N,1)
232 {
233 cost[i][j] = abs( X[i].r-Y[j].r )+abs( X[i].c-Y[j].c );
234 }
235 }
236
237 printf("%d\n",KM_PM(false));
238 }
239 return 0;
240 }

posted @ 2011-03-07 10:38  AC2012  阅读(859)  评论(0编辑  收藏  举报