zoukankan      html  css  js  c++  java
  • 网络流费用流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);
    }
    

      

  • 相关阅读:
    this指向
    作用域链
    入门
    一、servlet之初见
    jdbc之mysql
    第六章、树和二叉树
    第七章、暴力求解法
    机试
    第十三章、字符串
    栈和队列
  • 原文地址:https://www.cnblogs.com/342zhuyongqi/p/9830720.html
Copyright © 2011-2022 走看看