最近看了一下費用流,找到適合模仿的程式對著資料看了一下,覺得比當初學的最大流還簡單(當然現在與四個月以前的水平是不可同日而語了),基本思路是以費用為邊權,用最短路演算法找最小費用的增廣路。主程式有點類似最大流的EK演算法,而且找最小費用增光路基本上都是用SPFA來實現,也是相當熟悉的演算法了。模仿了一個,又自己打了一個,第二個程式基本十二分鐘就敲完了,不過兩個程式都Debug了好久,都是變數打錯或是漏掉語句的低級錯誤……
有空要研究一下最佳二分圖匹配,zkw費用流之類的演算法,再熟悉一下建模,參數做做線性規劃與網路流24題吧,再找些經典的題目,基礎的網路流應該不成問題了。
附最小費用流程式:
const oo=19930508;var dist,path:array[0..1000] of longint; f,cost:array[0..1000,0..1000] of longint; i,j,k,m,n,x:longint; maxflow,mincost,flow:longint; q:array[0..100000] of longint; flag:array[0..10000] of boolean; head,tail:longint; now,pre:longint; s,t:longint; y,z,w:longint;function min(a,b:longint):longint;begin if a<b then exit(a) else exit(b);end;function spfa:boolean;begin fillchar(flag,sizeof(flag),0); for i:=1 to n do dist[i]:=oo; head:=0; tail:=1; q[1]:=s; flag[s]:=true; dist[s]:=0; while head<tail do begin inc(head); i:=q[head]; flag[i]:=false; for j:=1 to n do if (f[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 inc(tail); q[tail]:=j; flag[j]:=true; end; end; end; exit(dist[t]<>oo);end;procedure init;begin readln(n,m); for i:=1 to n do begin for j:=1 to n do cost[i,j]:=oo; cost[i,i]:=0; end; for i:=1 to m do begin readln(x,y,z,w); f[x,y]:=z; cost[x,y]:=w; end; s:=1; t:=n;end;procedure main;begin while spfa do begin now:=t; flow:=oo; while now<>s do begin pre:=path[now]; flow:=min(flow,f[pre,now]); now:=pre; end; inc(maxflow,flow); now:=t; while now<>s do begin pre:=path[now]; dec(f[pre,now],flow); inc(f[now,pre],flow); cost[now,pre]:=-cost[pre,now]; mincost:=mincost+cost[pre,now]*flow; now:=pre; end; end;end;procedure print;begin writeln(mincost);end;begin assign(input,'data.in'); reset(input); assign(output,'data.out'); rewrite(output); init; main; print; close(input); close(output);end.