最近看了一下费用流,找到适合模仿的程序对着资料看了一下,觉得比当初学的最大流还简单(当然现在与四个月以前的水平是不可同日而语了),基本思路是以费用为边权,用最短路算法找最小费用的增广路。主程序有点类似最大流的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.