网络流费用流Ek算法讲解

前一篇博客写的是最大流。先简要说一下思路,方便下面的讲解。

最大流求解是先跑一遍bfs,把每个点定义一个深度,跑dfs的同时连接一条反向边方便反悔,避免不必要的时间。

现在说一下费用流。

费用流的全称是最小费用最大流(或最大费用最大流),保证最小费用的情况下跑最大流。

最小费用?

BFS  ->  SPFA成功解决。

我们不需要再给每个点定义深度,而是直接把费用当成边权求一遍到原点的最短路。

但是,流量的反向边初始值为0,费用是0吗?

显然不是,因为如果不需要走这条边显然是不需要费用的,所以正向边+反向边的费用为0.显然费用为-cost。

下一个问题,如果我们找到了最短路,如何寻找路径把费用累加并更改流量?

SPFA解决!

之后我们当前dfs的流量需要用一个数组存起来,而不是一个变量。

之后就没什么了,不会的问我。

P3381 【模板】最小费用最大流

题目描述

如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。

输入格式:

 第一行包含四个正整数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);
}

  

原文地址:https://www.cnblogs.com/342zhuyongqi/p/9830720.html