题意:网络中有两台计算机s,t。现在每秒钟要从s到t传输大小为F的数据到t。该网络中一共有N台计算机,其中有一些靠单向电缆相连接每条电缆用(from,to,cap,cost)表示从from发送给to,最大容量是cap,单位传输费用是cost。问传输数据最小的花费是多少?
解决最小费用流的一般思路是:每次都沿着最短路进行增广,增广一次之后累加本次增广的总费用,同时修改剩余的流量F,当F≤0时或dist[t]==INF时退出。
(1)概述:题目要求在存在流量为F的前提下,总花费最少。这类问题就是最小费用流问题。该问题可以采用加入“势函数”后的Dijkstra算法解决。因为对于每条边e=(u,v),有如下事实成立:h(v)≤h(u)+e.cost(其中h[u]表示s到u的最短距离)。因此令dist[v]=dist[u]+e.cost+h[u]-h[v],。那么所有的dist值必然大于等于0,这样就能用Dijkstra算法求解了。下面代码中用了一个优先队列,每次优先出列dist值小的元素。整个算法的时间复杂度是O(F*ElogV)(F是流量,E是边数,V是顶点数)。
#include
#include
#include
#include
#include
#include
#include
#include
这就是最小费用最大流问题:既要求出最大流,又要求出达到最大流时候的最小费用。一般的解决办法是利用Bellman-Ford算法沿着最短路增广,每增广一次算一次费用,直到不存在最短路为止,此时便找到了最大流,同时也得到了最小费用。为了减少溢出的可能,cost类型改为long long。
(1)概述:整个算法与之前的Bellman-Ford算法差不多,只不过多了一个cost参数而已,注意:初始的网络可以有负权边,但不允许有负权圈,否则算法失效。
#define N 1000
#define INF 100000000
struct Edge
{
int from,to,cap,flow,cost;
};
struct MCMF
{
int n,m,s,t;
vectoredges;
vectorG[N];
int inq[N];//是否在队列中
int d[N];//Bellman-Ford
int p[N];//上一条弧
int a[N];//可改进量
void init(int n)
{
this->n=n;
for(int i=0;iq;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
inq[u]=0;
for(int i=0;ie.flow&&d[e.to]>d[u]+e.cost)//松弛操作
{
d[e.to]=d[u]+e.cost;
p[e.to]=G[u][i];//记录父边
a[e.to]=min(a[u],e.cap-e.flow);//更新可改进量,等于min{到达u时候的可改进量,e边的残量}
if(!inq[e.to]){q.push(e.to);inq[e.to]=1;}
}
}
}
if(d[t]==INF)//仍为初始时候的INF,s-t不连通,失败退出
return false;
flow+=a[t];
cost+=(long long)d[t]*a[t];//d[t]一方面代表了最短路长度,另一方面代表了这条最短路的单位费用的大小
int u=t;
while(u!=s)//逆向修改每条边的流量值
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
u=edges[p[u]].from;
}
return true;
}
int MincostMaxflow(int s,int t,long long&cost)//返回最大流,同时用引用返回达到最大流时的最小费用
{
int flow=0;
cost=0;
while(BellmanFord(s,t,flow,cost));//直到不存在最短路时停止
return flow;
}
};