网络流--费用流Ek算法讲解
前一篇博客写的是最大流。先简要说一下思路,方便下面的讲解。
最大流求解是先跑一遍bfs,把每个点定义一个深度,跑dfs的同时连接一条反向边方便反悔,避免不必要的时间。
现在说一下费用流。
费用流的全称是最小费用最大流(或最大费用最大流),保证最小费用的情况下跑最大流。
最小费用?
BFS -> SPFA成功解决。
我们不需要再给每个点定义深度,而是直接把费用当成边权求一遍到原点的最短路。
但是,流量的反向边初始值为0,费用是0吗?
显然不是,因为如果不需要走这条边显然是不需要费用的,所以正向边+反向边的费用为0.显然费用为-cost。
下一个问题,如果我们找到了最短路,如何寻找路径把费用累加并更改流量?
SPFA解决!
之后我们当前dfs的流量需要用一个数组存起来,而不是一个变量。
之后就没什么了,不会的问我。
题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
输入格式:
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
输出格式:
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。
样例输入:
4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5
样例输出:
50 280
code:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define N 100000
int n,m,S,T;
int f[N];
int now[N];
int head[N];
int to[N];
int val[N];
int nex[N];
int cost[N];
int idx=1;
int inq[N];
int pre[N];
int maxflow;
int ans;
int a,b,c,d;
int nowflow[N];
void addedge(int a,int b,int c,int d)
{
nex[++idx]=head[a];
head[a]=idx;
to[idx]=b;
val[idx]=c;
cost[idx]=d;
}
bool spfa(int S,int T)
{
queue<int > q;
memset(f,0x3f,sizeof(f));
memset(inq,0,sizeof(inq));
memset(nowflow,0x3f,sizeof(nowflow));
q.push(S);
f[S]=0;
inq[S]=1;
//cost[S]=1<<30;
while(!q.empty())
{
int x=q.front();
inq[x]=0;
q.pop();
for(int i=head[x];i;i=nex[i])
{
if(val[i]>0&&f[to[i]]>f[x]+cost[i])
{
f[to[i]]=f[x]+cost[i];
nowflow[to[i]]=min(nowflow[x],val[i]);
pre[to[i]]=i;
if(!inq[to[i]])
{
inq[to[i]]=1;
q.push(to[i]);
}
}
}
}
if(f[T]>=0x3f3f3f3f)
return 0;
return 1;
}
void EK()
{
int x=T;
while(x!=S)
{
int i=pre[x];
val[i]-=nowflow[T];
val[i^1]+=nowflow[T];
x=to[i^1];
}
maxflow+=nowflow[T];
ans+=f[T]*nowflow[T];
}
int main()
{
scanf("%d%d%d%d",&n,&m,&S,&T);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
addedge(a,b,c,d);
addedge(b,a,0,-d);
}
while(spfa(S,T))
EK();
printf("%d %d",maxflow,ans);
}

浙公网安备 33010602011771号