2516

1 /*
2 应用KM算法,求最小权和
3
4 当然也可以使用最小费用最大流来做
5
6 此题目非常的有意思
7
8 首先对于KM的使用,改怎么用?
9
10 因为K个商品之间没有什么关系,所以对每个商品建一个二分图,求出最小权和,就是最后的结果
11
12 然而对于每一幅二分图改怎么建立呢,因为KM是完备匹配,所以每个商人需要几个该商品,就需要几个点,也就是说左边的N个
13 商人要按照他们需要多少商品拆点,右边同样如此。这样一个活生生的带权二分图就呈现在我们眼前了
14 剩下的就是KM的事情啦
15 哈哈~~
16 */
17
18 // include file
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <cmath>
23 #include <cctype>
24 #include <ctime>
25
26 #include <iostream>
27 #include <sstream>
28 #include <fstream>
29 #include <iomanip>
30 #include <bitset>
31 #include <strstream>
32
33 #include <algorithm>
34 #include <string>
35 #include <vector>
36 #include <queue>
37 #include <set>
38 #include <list>
39 #include <functional>
40
41 using namespace std;
42
43 // typedef
44 typedef long long LL;
45 typedef unsigned long long ULL;
46
47 //
48 #define read freopen("in.txt","r",stdin)
49 #define write freopen("out.txt","w",stdout)
50 #define FORi(a,b,c) for(int i=(a);i<(b);i+=c)
51 #define FORj(a,b,c) for(int j=(a);j<(b);j+=c)
52 #define FORk(a,b,c) for(int k=(a);k<(b);k+=c)
53 #define FORp(a,b,c) for(int p=(a);p<(b);p+=c)
54 #define FORii(a,b,c) for(int ii=(a);ii<(b);ii+=c)
55 #define FORjj(a,b,c) for(int jj=(a);jj<(b);jj+=c)
56 #define FORkk(a,b,c) for(int kk=(a);kk<(b);kk+=c)
57
58 #define FF(i,a) for(int i=0;i<(a);i+++)
59 #define FFD(i,a) for(int i=(a)-1;i>=0;i--)
60 #define Z(a) (a<<1)
61 #define Y(a) (a>>1)
62
63 const double eps = 1e-6;
64 const double INFf = 1e10;
65 const int INFi = 1000000000;
66 const double Pi = acos(-1.0);
67
68 template<class T> inline T sqr(T a){return a*a;}
69 template<class T> inline T TMAX(T x,T y)
70 {
71 if(x>y) return x;
72 return y;
73 }
74 template<class T> inline T TMIN(T x,T y)
75 {
76 if(x<y) return x;
77 return y;
78 }
79 template<class T> inline void SWAP(T &x,T &y)
80 {
81 T t = x;
82 x = y;
83 y = t;
84 }
85 template<class T> inline T MMAX(T x,T y,T z)
86 {
87 return TMAX(TMAX(x,y),z);
88 }
89
90
91 // code begin
92 #define MAXN 160
93 #define MAXV 50000
94 int N,M,K; // 右顶点个数
95 int Xs,Ys; // 左顶点个数
96 int cost[MAXN][MAXN]; //代价矩阵
97 int lx[MAXN]; //顶标用
98 int ly[MAXN];
99 bool S[MAXN]; //交替树用
100 bool T[MAXN];
101 int mt[MAXN]; //匹配用的
102 vector<int> Ng[MAXN/3];
103 vector<int> Mg[MAXN/3];
104
105 bool hungarian_MM(int i)
106 {
107 S[i] =true;
108 FORj(0,Ys,1)
109 {
110 if( !T[j] && lx[i]+ly[j]==cost[i][j] )
111 {
112 T[j]=true;
113 if( mt[j]==-1 || hungarian_MM(mt[j]) )
114 {
115 mt[j] = i;
116 return true;
117 }
118 }
119 }
120 return false;
121 }
122
123 int KM_PM(bool flag=true) // true的时候是最大权和,false的时候是最小权和
124 {
125 if(!flag)
126 {
127 FORi(0,Xs,1)
128 {
129 FORj(0,Ys,1)
130 {
131 cost[i][j] = -cost[i][j];
132 }
133 }
134 }
135
136 // 初始化标号
137 FORi(0,Xs,1)
138 {
139 lx[i] = -INFi;
140 ly[i] = 0;
141 FORj(0,Ys,1)
142 {
143 lx[i] = TMAX(lx[i],cost[i][j]);
144 }
145 }
146
147 //
148 memset(mt,-1,sizeof(int)*MAXN);
149 int cnt1=0,cnt;
150 FORi(0,Xs,1)
151 {
152 while(true)
153 {
154 memset(S,0,sizeof(bool)*MAXN);
155 memset(T,0,sizeof(bool)*MAXN);
156 if( hungarian_MM(i) )
157 {
158 break;
159 }
160 // 找d
161 int d = INFi;
162 FORj(0,Xs,1)
163 {
164 if(S[j])
165 {
166 FORk(0,Ys,1)
167 {
168 if(!T[k])
169 {
170 d = TMIN(d,lx[j]+ly[k]-cost[j][k]);
171 }
172 }
173 }
174 }
175
176 // 更新
177 FORj(0,Xs,1)
178 {
179 if(S[j])
180 lx[j] -= d;
181 }
182 FORj(0,Ys,1)
183 {
184 if(T[j])
185 ly[j] += d;
186 }
187
188 }
189
190 }
191
192
193 // 找到一个最优匹配
194 int ans = 0;
195 FORi(0,Ys,1)
196 {
197 if(mt[i]!=-1)
198 ans += cost[mt[i]][i];
199 }
200 if(!flag)
201 {
202 ans = -ans;
203 FORi(0,Xs,1)
204 {
205 FORj(0,Ys,1)
206 {
207 cost[i][j] = -cost[i][j];
208 }
209 }
210 }
211
212 return ans;
213 }
214
215 int main()
216 {
217 read;
218 write;
219 int a;
220 while(scanf("%d %d %d",&N,&M,&K)!=-1)
221 {
222 if(N+M+K==0)
223 break;
224
225 FORi(0,N,1)
226 {
227 Ng[i].clear();
228 FORj(0,K,1)
229 {
230 scanf("%d",&a);
231 Ng[i].push_back(a);
232 }
233 }
234
235 FORi(0,M,1)
236 {
237 Mg[i].clear();
238 FORj(0,K,1)
239 {
240 scanf("%d",&a);
241 Mg[i].push_back(a);
242 }
243 }
244 //对于每个货物都有一个代价矩阵
245 int i,ans = 0,t;
246 for(i=0;i<K;i++)
247 {
248 Xs = 0;
249 Ys = 0;
250
251 FORj(0,N,1)
252 Xs+=Ng[j][i];
253 FORj(0,M,1)
254 Ys+=Mg[j][i];
255
256 int zz,yy;
257
258 zz = 0;
259 //首先输入代价矩阵
260 FORj(0,N,1)
261 {
262 yy = 0;
263 FORk(0,M,1)
264 {
265 scanf("%d",&a);
266
267 FORjj(zz,zz+Ng[j][i],1)
268 {
269 FORkk(yy,yy+Mg[k][i],1)
270 {
271 cost[jj][kk]=a;
272 }
273 }
274 yy+=Mg[k][i];
275 }
276 zz+=Ng[j][i];
277 }
278
279 if(Xs>Ys)
280 {
281 ans = -1;
282 break;
283 }
284
285 int sub = Ys-Xs;
286 while(Xs<Ys)
287 {
288 //添加一个Xs到Ys的所有的相同价值的边
289 FORk(0,Ys,1)
290 {
291 cost[Xs][k]=1;
292 }
293 Xs++;
294 }
295
296 ans += KM_PM(false)-sub;
297
298 }
299 for(i++;i<K;i++)
300 {
301 FORj(0,N,1)
302 {
303 FORk(0,M,1)
304 {
305 scanf("%d",&a);
306 }
307 }
308 }
309 printf("%d\n",ans);
310 }
311 return 0;
312 }
posted @ 2011-03-07 14:58  AC2012  阅读(495)  评论(0编辑  收藏  举报