带权二分图匹配:KM算法与费用流建模
KM似乎还是有点难以理解,看了半天资料仍有半懂不懂的感觉,或许以后多想想、画画,做些题能加深理解吧,当初学匈牙利的时候就是这样。
相关资料
题目:ural1076
我的KM是抄nocow上的题解的,只不过出于习惯改了一个变量名。费用流的思路也是按nocow上的,计算出i种箱子装j种垃圾的费用然后求最小费用。根据自己的理解按照KM上的统计所有垃圾量-最大费用的程序也写了一个,不过陷入死循环中,有时间再调试吧。
我的ural1076 KM算法程序
const oo=199305080; maxn=200; var lx,ly,link:array[0..maxn] of longint; w:array[0..maxn,0..maxn] of longint; i,j,k,m,n,d,tot:longint; x,y:array[0..maxn] of boolean; function max(a,b:longint):longint; begin if a<b then exit(B) else exit(a); end; procedure init; begin readln(n); for i:=1 to n do for j:=1 to n do begin read(w[i,j]); inc(tot,w[i,j]); end; end; function dfs(v:longint):boolean; var i:longint; begin if v=0 then exit(true); x[v]:=true; for i:=1 to n do if (y[i]=false) and (lx[v]+ly[i]=w[v,i]) then begin y[i]:=true; if dfs(link[i]) then begin link[i]:=v; exit(true); end end; exit(false); end; procedure main; begin for i:=1 to n do for j:=1 to n do lx[i]:=max(lx[i],w[i,j]); for k:=1 to n do while true do begin fillchar(x,sizeof(x),0); fillchar(y,sizeof(y),0); if dfs(k) then break; d:=oo; for i:=1 to n do if x[i] then for j:=1 to n do if (not y[j]) and (lx[i]+ly[j]-w[i,j]<d) then d:=lx[i]+ly[j]-w[i,j]; for i:=1 to n do begin if x[i] then dec(lx[i],d); if y[i] then inc(ly[i],d); end end; end; procedure print; begin for i:=1 to n do dec(tot,w[link[i],i]); writeln(tot); end; begin init; main; print; end. 来一个费用流:
const maxn=400; oo=199305080; var c,cost,w:array[0..maxn,0..maxn] of longint; flow,i,j,k,m,n,mincost,tot,s,t,pre,now,sum:longint; path:array[0..maxn] of longint; q,dist:array[0..100000] of longint; flag:array[0..10000] of boolean; function spfa:boolean; var i,j,k,head,tail:longint; begin head:=0; tail:=1; q[1]:=s; fillchar(flag,sizeof(flag),0); flag[s]:=true; for i:=1 to tot do dist[i]:=oo; dist[s]:=0; while head<tail do begin inc(head); i:=q[head]; flag[i]:=false; for j:=1 to tot do begin if (c[i,j]>0) and (dist[j]>dist[i]+cost[i,j]) then begin dist[j]:=dist[i]+cost[i,j]; path[j]:=i; if not flag[j] then begin flag[j]:=true; inc(tail); q[tail]:=j; end; end; end; end; exit(dist[t]<>oo); end; procedure init; begin readln(n); for i:=1 to n do begin sum:=0; for j:=1 to n do begin read(w[i,n+j]); inc(sum,w[i,n+j]); end; for j:=1 to n do begin cost[i,n+j]:=sum-w[i,n+j]; cost[n+j,i]:=-cost[i,n+j]; c[i,n+j]:=1; end; end; s:=n*2+1; t:=n*2+2; tot:=t; for i:=1 to n do c[s,i]:=1; for i:=1 to n do c[n+i,t]:=1; end; function min(a,b:longint):longint; begin if a<b then exit(a) else exit(b); end; procedure main; begin while spfa do begin now:=t; flow:=oo; while now<>s do begin pre:=path[now]; flow:=min(flow,c[pre,now]); now:=pre; end; now:=t; while now<>s do begin pre:=path[now]; dec(c[pre,now],flow); inc(c[now,pre],flow); inc(mincost,flow*cost[pre,now]); now:=pre; end; end; end; procedure print; begin writeln(mincost); end; begin init; main; print; end.