关于最小费用最大流的问题描述,这个ppt讲的很好 https://wenku.baidu.com/view/38c158d4c1c708a1284a44af.html
初始化费用矩阵和链路容量矩阵,费用矩阵中如果两个点之间不相连,则代价为inf,而链路容量矩阵中两个点不直连,则链路容量为0.
然后怎样在迭代中更新费用矩阵,有三条规则:
1、如果某条链路没有任何流量通过,则该条链路的费用不变。
2、如果某条链路上有流量但不饱和,则该条链路原本的前向链路的代价为a的话,则反向添加一条链路,其代价为-a。(例如原本图中是点i到j,费用为a,则现在代价矩阵中添加一条从j到i的链路,代价为-a),具体理解:称i到j为前向链路,j到i为后向链路,这样表明,如果后面继续会从前向链路上增加流量的话,费用会增加a*走过的流量,如果链路一开始走多了,那么要回退,即走后向链路,那么费用会以-a*退的流量而减少。
3、如果某条链路达到饱和,那么原来前向链路的费用为inf(即断开),后向链路的费用为-a,表示已经不能再从前向链路增加流量了,只能从后向退回原来多走的流量。
然后更新完代价矩阵之后,再根据实际走的流量情况更新走的流量矩阵。最终完成迭代,得到最小费用最大流。
附上matlab代码:
function [ f,MinCost,MaxFlow ] = MaxFlowMinCost( a,c,V,s,t )
%% 输入参数列表
% a 单位流量的费用矩阵
% c 链路容量矩阵
% V 最大流的预设值,可为无穷大
% s 源节点
% t 目的节点
%% 输出参数列表
% f 链路流量矩阵
% MinCost 最小费用
% MaxFlow 最大流量
%% 说明
%不断更新a和c矩阵,如果某两点之间的链路容量饱和,则该链路费用为inf,链路容量为0
%% 第一步:初始化
NodeNum=size(a,1);%节点数目
f=zeros(NodeNum,NodeNum);%流量矩阵,初始时为零流
MaxFlow=0;%最大流量,初始时也为零
MinCost=0;%初始化最小费用
w=a;%权值费用矩阵
%% 第二步:迭代过程
while MaxFlow<V%停止条件为达到最大流的预设值
[cost,path] = Floyd(w,s,t);
%判断从s到t是否已经无路可走
if cost==inf
break;
end
%求一条最小花费路径上的最大流量
minflow=[];%以花费为权值的最小路径上的能通过的最大流量
for i=1:(length(path)-1)
if c(path(i),path(i+1))>f(path(i),path(i+1))
minflow=[minflow,c(path(i),path(i+1))-f(path(i),path(i+1))];
elseif c(path(i+1),path(i))==f(path(i+1),path(i))
minflow=[minflow,c(path(i+1),path(i))];
else
disp('出错啦1!');
end
end
minflow=min(minflow);
disp(['minflow为: ', num2str(minflow)]);
disp(path);
MaxFlow=MaxFlow+minflow;
if MaxFlow>=V%如果最后流量过剩
minflow=minflow-(MaxFlow-V);
MinCost=MinCost+(cost*minflow);
for i=1:(length(path)-1)
if c(path(i),path(i+1))>f(path(i),path(i+1))
f(path(i),path(i+1))=f(path(i),path(i+1))+minflow;
elseif c(path(i+1),path(i))==f(path(i+1),path(i))
f(path(i+1),path(i))=f(path(i+1),path(i))-minflow;
else
disp('出错啦2!');
end
end
MaxFlow=V;
for i=1:(length(path)-1)
if c(path(i),path(i+1))==f(path(i),path(i+1))%饱和链路
w(path(i+1),path(i))=-w(path(i),path(i+1));
w(path(i),path(i+1))=inf;
elseif c(path(i),path(i+1))>f(path(i),path(i+1))
w(path(i+1),path(i))=-w(path(i),path(i+1));
elseif c(path(i+1),path(i))>f(path(i+1),path(i))
w(path(i),path(i+1))=-w(path(i+1),path(i));
else
disp('出错啦!3');
end
end
break;
end
MinCost=MinCost+(cost*minflow);
for i=1:(length(path)-1)
if c(path(i),path(i+1))>f(path(i),path(i+1))
f(path(i),path(i+1))=f(path(i),path(i+1))+minflow;
elseif c(path(i+1),path(i))==f(path(i+1),path(i))
f(path(i+1),path(i))=f(path(i+1),path(i))-minflow;
else
disp('出错啦4!');
end
end
%更新a和c矩阵
for i=1:(length(path)-1)
if c(path(i),path(i+1))==f(path(i),path(i+1))%饱和链路
w(path(i+1),path(i))=-w(path(i),path(i+1));
w(path(i),path(i+1))=inf;
elseif c(path(i),path(i+1))>f(path(i),path(i+1))
w(path(i+1),path(i))=-w(path(i),path(i+1));
elseif c(path(i+1),path(i))>f(path(i+1),path(i))
w(path(i),path(i+1))=-w(path(i+1),path(i));
else
disp('出错啦!5');
end
end
end
end
function [ MinCost,path ] = Floyd( w,s,t ) %w:输入图的邻接矩阵 %s:源节点标号 %t:目的节点标号 %MinCost:费用 %path:最短路径 %D:D为路径的邻接矩阵 %path_matrix:路径所经过的端点 n=size(w,1); %设初值 D=w; path_matrix=zeros(n);%生成n*n的矩阵 for i=1:n for j=1:n if D(i,j)~=inf path_matrix(i,j)=j; end end end %生成路径矩阵 %迭代,更新D path for k=1:n for i=1:n for j=1:n if D(i,k)+D(k,j)<D(i,j) D(i,j)=D(i,k)+D(k,j);%更新路径的权值 path_matrix(i,j)=path_matrix(i,k);%注意这里因为存的都是后一个点,所以(k,j)存的还是j,所以不用更新 end end end end %%输出最小代价和路径 MinCost=D(s,t); if MinCost==inf%注意这里加一个判断,不然当面临s到t无路径时会出错 path=[]; return end path=[s]; tmp=s; while tmp~=t tmp=path_matrix(tmp,t); path=[path,tmp]; end end