ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

图论专题-网络流-学习笔记:dinic 求解费用流

2022-04-17 15:00:15  阅读:165  来源: 互联网

标签:图论 int Flow 笔记 Edge dinic now dis


目录

1. 前言

本篇博文将会重点讲解 dinic 求解费用流。

费用流全称:最小费用最大流,其一般的问题描述如下:

给出一张网络 \(G=<V,E>\),每条边有两个权值:\(f,v\)。

\(f\) 表示这条边的最大流量,\(v\) 表示单位花费,也就是说从这条边每流过一单位流量就要增加 \(v\) 的花费。

现在要求这张网络的最小费用最大流,也就是在保证总流量最大的情况下总费用最小。

之前笔者写过一篇 EK 求解费用流,效率挺高,但是根据某法律:卡 EK 合法,卡 dinic 不合法!(笔者是真的不知道这法律哪来的)

于是 dinic 求解费用流还是需要掌握的。

在往下看之前,读者应当对以下知识有所了解:

  1. dinic 求解最大流。
  2. SPFA 求解最短路。

没有学过?

  1. dinic 求解最大流:算法学习笔记:网络流#3——dinic 求解最大流
  2. SPFA 求解最短路:P3371 【模板】单源最短路径(弱化版) 题解

2. 详解

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

首先回顾一下 dinic 求解最大流的思路:

先采用 BFS 分层,在相邻两层之间推流,采用 DFS 形式推流,一次可以找到多条增广路,采用当前弧优化。

那么 dinic 如何求费用流呢?

因为出现了最小费用这一限制条件,因此我们不能简单的对图分层,而是先需要跑一遍最短路径。

跑最短路径的时候要特别注意:反向边的费用为正向边费用的相反数,因此 不能直接使用 dijkstra 算法。

然后就可以愉快的 dinic 了~

因为此时已经满足了最短路径这一限制条件,也就是保证费用最小,因此此时直接类比 dinic 跑 DFS 就好了。

需要注意的是这里的 dinic 有一个特别的限制条件:走过的点不能再走,这是为了防止被环卡掉。

记录最小费用在中间记录就好。

代码:

/*
========= Plozia =========
    Author:Plozia
    Problem:P3381 【模板】最小费用最大流——dinic 写法
    Date:2021/3/30
========= Plozia =========
*/

#include <bits/stdc++.h>
using std::queue;

typedef long long LL;
const int MAXN = 5e3 + 10, MAXM = 5e4 + 10;
const LL INF = 0x3f3f3f3f3f3f3f3f;
int n, m, s, t, Head[MAXN], cnt_Edge = 1, cur[MAXN];
LL dis[MAXN], ans_Flow, ans_Spend;
bool book[MAXN], vis[MAXN];
struct node{int to; LL Flow, val; int Next;} Edge[MAXM << 1];

int read()
{
    int sum = 0, fh = 1; char ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
    for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
    return (fh == 1) ? sum : -sum;
}
void add_Edge(int u, int v, int w, int c) {++cnt_Edge; Edge[cnt_Edge] = (node){v, w, c, Head[u]}; Head[u] = cnt_Edge;}
LL Min(LL fir, LL sec) {return (fir < sec) ? fir : sec;}

bool SPFA()
{
    queue <int> q; q.push(s);
    memset(book, 0, sizeof(book));
    memset(dis, 0x3f, sizeof(dis));
    book[s] = 1; dis[s] = 0;
    while (!q.empty())
    {
        int x = q.front(); q.pop(); book[x] = 0;
        for (int i = Head[x]; i; i = Edge[i].Next)
        {
            int u = Edge[i].to;
            if (Edge[i].Flow && dis[u] > dis[x] + Edge[i].val)
            {
                dis[u] = dis[x] + Edge[i].val;
                if (!book[u]) {q.push(u); book[u] = 1;}
            }
        }
    }
    return dis[t] != INF;
}

LL dfs(int now, LL Flow)
{
    if (now == t || Flow == 0) return Flow;
    vis[now] = 1; LL used = 0;
    for (int i = cur[now]; i; i = Edge[i].Next)
    {
        int u = Edge[i].to; cur[now] = i;
        if (Edge[i].Flow && !vis[u] && dis[now] + Edge[i].val == dis[u])
        {
            LL Minn = dfs(u, Min(Flow - used, Edge[i].Flow));
            if (Minn)
            {
                Edge[i].Flow -= Minn; Edge[i ^ 1].Flow += Minn; used += Minn;
                ans_Spend += Edge[i].val * Minn; if (used == Minn) {vis[now] = 0; return used;}
            }
        }
    }
    vis[now] = 0;
    if (used == 0) vis[now] = 1;
    return used;
}

void dinic()
{
    while (SPFA())
    {
        LL d; memset(vis, 0, sizeof(vis));
        for (int i = 1; i <= n; ++i) cur[i] = Head[i];
        while ((d = dfs(s, INF)) != 0) {ans_Flow += d;}
    }
}

int main()
{
    n = read(), m = read(), s = read(), t = read();
    for (int i = 1; i <= m; ++i)
    {
        int u = read(), v = read(), w = read(), c = read();
        add_Edge(u, v, w, c); add_Edge(v, u, 0, -c);
    }
    dinic(); printf("%lld %lld\n", ans_Flow, ans_Spend);
    return 0;
}

3. 总结

dinic 求解费用流的思路就是将 BFS 分层换成 SPFA 求解最短路,然后照常 DFS 就好。

标签:图论,int,Flow,笔记,Edge,dinic,now,dis
来源: https://www.cnblogs.com/Plozia/p/16155770.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有