首页 > 其他分享 >[luoguP3376] 网络最大流

[luoguP3376] 网络最大流

时间:2025-01-12 15:35:47浏览次数:1  
标签:include return 最大 int d% 网络 UI luoguP3376

题意

给出一个网络,求流量的最大值

sol

网络流板子题。
网络流是 OI 中比较常用的算法之一,以较高的建图难度深受出题人喜爱,不过近几年题目数量减少。
当然,在学习建图之前,需要先学会网络流的板子。

一些定义

(部分摘自 OI-Wiki)
网络是特殊的有向图 \(G=(V,E)\);
源点 \(s\) 是网络的起点,汇点 \(t\) 是网络的终点,\(s,t \in V\);
对于\(\forall (u,v) \in E\),其容量为 \(c(u,v)\),特别的,若 \((u,v) \notin E\),\(c(u,v) = 0\)
对于\(\forall (u,v) \in E\),其流量为 \(f(u,v)\),且满足以下性质:

  1. \(\forall (u,v) \in E, 0\le f(u,v) \le c(u,v)\)
  2. \(\forall u \in V - \{s,t\}, \sum_{x\in V} f(u,x) = \sum_{x\in V} f(x,u)\)

对于一个网络上的一个流,我们定义其流量 \(|f|=\sum_{x\in V} f(s,x) - \sum_{x\in V} f(x,s)\)
对于一个网络 \(G\),若 \(S\cap T=V\) 且 \(S\cup T=\varnothing\) 且 \(s \in S,t \in T\),则 {S,T} 是 \(G\) 的一个割,其容量 \(||S,T||=\sum_{u\in S}\sum_{v\in T} c(u,v)\)
对于网络 \(G\),其可能的最大的流量 \(f\) 即为 \(G\) 的最大流

Edmond-Karp

在残量网络中 BFS 找到一条增广路(从源点到汇点容量为正的路径),累加流量,最后更新残量网络。
理论复杂度上限 \(O(nm^2)\),实际可处理 \(10^3 \sim 10^4\) 的数据
代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
typedef unsigned int UI;
typedef long long LL;

constexpr int N = 205, M = 10005;
constexpr UI INF = 1 << 31;

int h[N], e[M], f[M], ne[M], idx;
int pre[N];
UI d[N];
bool st[N];
int n, m, S, T;

void add(int a, int b, int c){
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}

bool BFS(){
    memset(st, false, sizeof st);
    queue<int> q;
    st[S] = true, d[S] = INF;
    q.push(S);
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        for (int i = h[t]; ~i; i = ne[i]){
            int j = e[i];
            if (!st[j] && f[i]) {
                st[j] = true;
                pre[j] = i;
                d[j] = min(d[t], (UI) f[i]);
                if (j == T) return true;
                q.push(j);
            }
        }
    }
    return false;
}

LL EK(){
    LL res = 0;
    while (BFS()) {
        res += d[T];
        for (int u = T; u != S; u = e[pre[u] ^ 1]) 
            f[pre[u]] -= d[T], f[pre[u] ^ 1] += d[T];
    }

    return res;
}

int main(){
    scanf("%d%d%d%d", &n, &m, &S, &T);
    memset(h, -1, sizeof h);
    while (m -- ){
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }

    printf("%lld\n", EK());

    return 0;
}

Dinic

在残量网络中进行分层(防止出现环),然后爆搜每一条增广路,如果可行的话就累加
注意一部分优化:

  1. 在爆搜的过程中,如果发现当前节点的流出流量已经超过流入流量,则直接返回
  2. 在爆搜的过程中,如果发现某个节点无法提供任何流量,那么就在这个残量网络中删除这个节点
  3. 在爆搜的过程中,如果重复遍历某个点,那么继续上一次未搜索完的弧遍历(当前弧优化)

理论复杂度上限 \(O(n^2m)\),实际可处理 \(10^4 \sim 10^5\) 的数据。
代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
typedef unsigned int UI;

const int N = 1205, M = 240005;
const UI INF = 1 << 31;

int h[N], e[M], ne[M], idx;
UI f[M];
int d[N], cur[N];
int n, m, S, T;

void add(int a, int b, int c){
    e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}

bool bfs(){
    memset(d, -1, sizeof d);
    queue<int> q;
    q.push(S), d[S] = 0, cur[S] = h[S];
    while (!q.empty()) {
        int t = q.front(); q.pop();
        for (int i = h[t]; ~i; i = ne[i]){
            int j = e[i];
            if (d[j] == -1 && f[i]) {
                d[j] = d[t] + 1;
                cur[j] = h[j];
                if (j == T) return true;
                q.push(j);
            }
        }
    }
    return false;
}

UI find(int u, UI limit) {
    if (u == T) return limit;
    UI flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i]){ // 优化 1
        cur[u] = i; // 优化 3
        int j = e[i];
        if (d[j] == d[u] + 1 && f[i]) {
            int t = find(j, min(limit - flow, f[i]));
            if (!t) d[j] = -1; // 优化 2
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

int dinic(){
    int res = 0, flow;
    while (bfs()) while (flow = find(S, INF)) res += flow;
    return res;
}

int main(){
    scanf("%d%d%d%d", &n, &m, &S, &T);
    memset(h, -1, sizeof h);
    while (m -- ){
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }

    printf("%d\n", dinic());
}

Dinic 算法在大部分题目中都够用,因为卡 Dinic 是没有浮木的行为。
此外还有效率差不多的 ISAP 算法和相对更快的 HLPP 算法(理论上届复杂度 \(O(n^2\sqrt{m})\)),但是不会。

标签:include,return,最大,int,d%,网络,UI,luoguP3376
From: https://www.cnblogs.com/XiaoJuRuoUP/p/-/luoguP3376

相关文章

  • 《jspm二手车估值与销售网络平台》毕业设计项目
    大家好,我是俊星学长,一名在Java圈辛勤劳作的码农。今日,要和大家分享的是一款《jspm二手车估值与销售网络平台》毕业设计项目。项目源码以及部署相关事宜,请联系俊星学长,文末会附上联系信息哦。......
  • 《jspm二手车估值与销售网络平台》毕业设计项目
    大家好我是小村学长,混迹在java圈的辛苦码农。今天要和大家聊的是一款《jspm二手车估值与销售网络平台》毕业设计项目。项目源码以及部署相关请联系小村学长,文末附上联系信息。......
  • OpenStack 网络服务的原理和流程
    OpenStack的网络服务(Neutron)在云计算环境中起着至关重要的作用,它负责管理和提供网络连接,使得虚拟机和其他资源能够相互通信。以下将详细介绍OpenStack网络服务的原理和流程。一、OpenStack网络服务原理OpenStack的网络服务Neutron旨在为云计算环境提供灵活、可扩......
  • AAAI2020 | Ghost | 通过幽灵网络学习可迁移的对抗样本
    LearningTransferableAdversarialExamplesviaGhostNetworks摘要-Abstract引言-Introduction背景-Backgrounds幽灵网络-GhostNetworks实验-Experiments结论-Conclusion论文链接本文“LearningTransferableAdversarialExamplesviaGhostNetworks”一文......
  • 网络编程调试与故障排查
    网络编程调试与故障排查补天云火鸟博客创作软件补天云网站1QT网络编程基础1.1QT网络库简介与安装1.1.1QT网络库简介与安装QT网络库简介与安装章节标题,QT网络库简介与安装在现代软件开发领域,尤其是跨平台应用开发中,网络通信是不可或缺的一部分。Qt作为一种多平台......
  • 整数序列的元素最大跨度值题解
    【题目要求】计算序列的最大跨度值(最大值-最小值)一、求最大值如果a大于最大值,那么最大值就变成a,开始最大值要等于0。二、求最小值如果a小于最小值,那么最小值就变成a,开始最小值要等于1000。【题解代码】include<bits/stdc++.h>usingnamespacestd;intmain(){intn,a,......
  • Prometheus 是一个开源的监控和报警工具,主要用于收集、存储和查询来自不同服务和应用
    Prometheus是什么?Prometheus是一个开源的监控和报警工具,主要用于收集、存储和查询来自不同服务和应用程序的时间序列数据(如CPU使用率、内存消耗、网络流量等)。它特别适合用于微服务架构下的监控,因为它支持多种集成方式,并能够处理大规模的、高频的数据。Prometheus具有以下主......
  • 自动化安全加固(Automated Security Hardening)是指通过自动化工具和技术对计算机系统、
    自动化安全加固(AutomatedSecurityHardening)是指通过自动化工具和技术对计算机系统、网络设备、应用程序等进行安全配置和加固的过程。其目的是通过减少人为干预和错误,提高系统的安全性,防止潜在的安全漏洞和攻击。1. 是什么自动化安全加固的核心是自动化执行一系列安全加固措......
  • 【大厂面试AI算法题中的知识点】方向涉及:ML/DL/CV/NLP/大数据...本篇介绍训练网络的时
    【大厂面试AI算法题中的知识点】方向涉及:ML/DL/CV/NLP/大数据…本篇介绍训练网络的时候如何判断过拟合和欠拟合?【大厂面试AI算法题中的知识点】方向涉及:ML/DL/CV/NLP/大数据…本篇介绍训练网络的时候如何判断过拟合和欠拟合?文章目录【大厂面试AI算法题中的知识点】方......
  • 【Linux网络】Linux网络丢包场景,精准 “捕捉” 丢包踪迹
    在Linux网络的复杂脉络中,数据丢包就像隐匿的幽灵,悄无声息地破坏着网络的顺畅运行。你是否曾困惑,为何关键数据在传输途中突然消失,而排查起来却如同大海捞针?别担心,今天我们将深入Linux网络丢包场景,掌握精准“捕捉”丢包踪迹的秘诀,让这些隐匿的问题无所遁形。一、Linux网络丢......