網絡流基本概念及實現算法

基本概念

流網絡

在這里插入圖片描述
對于一個有向圖, 抽象成水管里的水的模型, 每根管子有容量限制, 計為 G = ( V , E ) G = (V, E) G=(V,E), 首先不考慮反向邊

在這里插入圖片描述
對于任意無向圖, 都可以將反向邊轉化為上述形式

如果一條邊不存在, 定義為容量為 0 0 0, 形式上來說就是 c ( u , v ) = 0 c(u, v) = 0 c(u,v)=0

可行流

對于每一個流網絡考慮一個可行流 f f f, 指定每條邊的流量, 需要滿足兩個條件

  • 容量限制 0 ≤ f ( u , v ) ≤ c ( u , v ) 0 \le f(u, v) \le c(u, v) 0f(u,v)c(u,v)
  • 流量守恒, 對于每個點來說, 流進去多少, 流出來多少, 形式化來說

∑ ( v , u ) f ( v , u ) = ∑ ( u , v ) f ( u , v ) \sum_{(v, u)} f(v, u) = \sum _{(u, v)} f(u, v) (v,u)?f(v,u)=(u,v)?f(u,v)
對于一個可行流, 從源點流向匯點的流量定義為 ∣ f ∣ |f| f, 每秒從源點流出的流量, 或者流入匯點的流量, 每秒凈往外流出的流量

∣ f ∣ = ∑ ( s , v ) f ( s , v ) ? ∑ ( v , s ) f ( v , s ) |f| = \sum _{(s, v)} f(s, v) - \sum _{(v, s)} f(v, s) f=(s,v)?f(s,v)?(v,s)?f(v,s)

最大流指的是流量值最大的可行流

殘存網絡

殘存網絡是對于流網絡某一個可行流
在這里插入圖片描述
對于某個可行流 f 1 f_1 f1?, 殘存網絡 G f 1 G_{f_1} Gf1??
殘存網絡的點集與原圖完全一致 V f = V V_f = V Vf?=V, 但是邊集不僅包含原圖的邊還包含原圖的反向邊 E f = E + E ′ E_f =E + E ' Ef?=E+E

殘存網絡也是流網絡

對于殘存網絡的容量記為 c ′ ( u , v ) c'(u, v) c(u,v)

  • 對于原圖的邊, 那么 c ′ ( u , v ) = c ( u , v ) ? f ( u , v ) c'(u, v) = c(u, v) - f(u, v) c(u,v)=c(u,v)?f(u,v)
  • 對于原圖的反向邊, c ′ ( u , v ) = f ( v , u ) c'(u, v) = f(v, u) c(u,v)=f(v,u)

對于任意一個可行流 f f f, 都可以求出殘存網絡 G f G_{f} Gf?

記殘存網絡的可行流 f ′ f' f, f + f ′ f + f' f+f也是原來流網絡 G G G的一個可行流

新的流的流量值等于兩個流的流量值之和 ∣ f + f ′ ∣ = ∣ f ∣ + ∣ f ′ ∣ |f + f'| = |f| + |f'| f+f=f+f, 流量相加等同于每條邊相加

為什么新的流是原流網絡 G G G的可行流?

  • 是否滿足容量限制
  • 是否滿足流量守恒

增廣路徑

殘存網絡中, 從源點出發沿著**容量大于 0 0 0**的點走如果能走到匯點, 那么這一條路徑就是增廣路徑
在這里插入圖片描述

上述紅色路徑就是增廣路徑, 增廣路徑一定是一個可行流, 流量大于 0 0 0
如果 G f G_f Gf?總不存在增廣路徑, 斷言 f f f是原來流網絡的最大流

將點集 V V V分為兩個集合 S , T S, T S,T, 滿足以下條件

  • s ∈ S s \in S sS, t ∈ T t \in T tT
  • S ∪ T = V S \cup T = V ST=V, S ∩ T = ? S \cap T = \emptyset ST=?

在這里插入圖片描述
上述就是割的形式化描述

割的容量

在這里插入圖片描述
所有從 S S S指向 T T T的邊, 被稱為割的容量, 容量不考慮回來的邊

c ( S , T ) = ∑ u ∈ S , v ∈ T c ( u , v ) c(S, T) = \sum _{u\in S, v \in T} c(u, v) c(S,T)=uS,vT?c(u,v)

割的流量

所有從 S S S留到 T T T的流量減去從 T T T流向 S S S的流量, 也就是凈流量

f ( S , T ) = ∑ u ∈ S , v ∈ T f ( u , v ) ? ∑ u ∈ T , v ∈ S f ( u , v ) f(S, T) = \sum _{u \in S, v \in T} f(u, v) - \sum _{u \in T, v \in S} f(u, v) f(S,T)=uS,vT?f(u,v)?uT,vS?f(u,v)

對于一個流網絡來說, 如果流網絡確定, 那么割的容量確定, 但是因為一個流網絡存在多個可行流, 因此割的流量是取決于每個可行流的流量的

性質1: 最小割指的是最小割的容量, 對于任意一個割以及任意一個可行流, 割的流量小于等于割的容量, 形式化來說 f ( S , T ) ≤ c ( S , T ) f(S, T) \le c(S, T) f(S,T)c(S,T), 證明過程如下
在這里插入圖片描述
性質2: 對于流網絡的任意一個割和任意一個可行流都有 f ( S , T ) = ∣ f ∣ f(S, T)= |f| f(S,T)=f

根據性質1和性質2推出 ∣ f ∣ = f ( S , T ) ≤ c ( S , T ) |f| = f(S, T) \le c(S, T) f=f(S,T)c(S,T), 也就推出 ∣ f ∣ ≤ c ( S , T ) |f| \le c(S, T) fc(S,T), 也就是最大流小于等于最小割

最大流最小割定理

對于某個流網絡 G = ( V , E ) G = (V, E) G=(V,E), 以下三個結論相互等價

  1. 可行流 f f f是最大流
  2. f f f的殘存網絡中不存在增廣路徑
  3. 存在割 [ S , T ] [S, T] [S,T], 使得 c ( S , T ) = ∣ f ∣ c(S, T) = |f| c(S,T)=f

證明如下

1 1 1 2 2 2
反證法, 存在增廣路徑, 由上述增廣路徑定理可知, 當前可行流不是最大流

3 3 3 1 1 1
因為 ∣ f ∣ ≤ c ( S , T ) |f| \le c(S, T) fc(S,T), 對于結論 3 3 3, 存在一個割使得 ∣ f ∣ = c ( S , T ) |f| = c(S, T) f=c(S,T), 證明 f f f是否是最大流
最大流 ≥ ∣ f ∣ 最大流 \ge |f| 最大流f, 又因為 ∣ f ∣ = c ( S , T ) ≥ 最大流 |f| = c(S, T) \ge 最大流 f=c(S,T)最大流, 因此 f f f是最大流

由結論 3 3 3得知, 最小割 ≤ c ( S , T ) = ∣ f ∣ ≤ 最大流 最小割 \le c(S, T) = |f| \le 最大流 最小割c(S,T)=f最大流, 也就有最小割小于等于最大流, 上述性質2可知, 最大流小于等于最小割, 因此最大流等于最小割

2 2 2 3 3 3
如果當前殘存網絡不存在增廣路徑, 能否構造出一個, 使得 c ( S , T ) = ∣ f ∣ c(S, T) = |f| c(S,T)=f
構造一個合法的割
點集 S S S是在 G f G_f Gf? s s s沿著容量大于 0 0 0的邊走, 走到的所有點, 因為不存在增廣路徑, 因此 s s s走不到 t t t
點集 T T T V ? S V - S V?S
借助的 G f G_f Gf?構造的是原網絡 G G G里的割

判斷當前割的容量是否等于 ∣ f ∣ |f| f
在這里插入圖片描述
構造的割的性質如下

  1. f ( x , y ) = c ( x , y ) f(x, y) = c(x, y) f(x,y)=c(x,y)
  2. f ( a , b ) = 0 f(a, b) = 0 f(a,b)=0

對于性質1, 如果 f ( x , y ) < c ( x , y ) f(x, y) < c(x, y) f(x,y)<c(x,y), 那么在殘存網絡中仍然會有 x x x連到 y y y的邊, 也就 x x x能遍歷到, y ∈ S y \in S yS, 與我們構造的矛盾
對于性質2, 如果 f ( a , b ) > 0 f(a, b) > 0 f(a,b)>0, 那么在殘存網絡中也是能遍歷到, a ∈ S a \in S aS, 與我們構造的矛盾

∣ f ∣ = ∑ u ∈ S , v ∈ T f ( u , v ) ? ∑ u ∈ T , v ∈ S f ( u , v ) |f| = \sum _{u \in S, v \in T} f(u, v) - \sum _{u \in T, v \in S} f(u, v) f=uS,vT?f(u,v)?uT,vS?f(u,v)

因為沒有反向邊, 并且每個邊的流量等于邊的容量, 因此

∣ f ∣ = ∑ u ∈ S , v ∈ T c ( u , v ) = c ( S , T ) |f| = \sum _{u \in S, v \in T} c(u, v) = c(S, T) f=uS,vT?c(u,v)=c(S,T)

最大流最小割定理證畢

最大流算法實現

F o r d – F u l k e r s o n Ford–Fulkerson FordFulkerson方法

求最大流的貪心方法, 維護殘存網絡, 不斷的在殘存網絡中尋找增廣路徑, 將當前流變為 f + f ′ f + f' f+f, 然后在新的流的殘存網絡中繼續尋找增廣路徑, 將當前殘存網絡 G f G_f Gf?變為 G f + f ′ G_{f + f'} Gf+f?

在這里插入圖片描述
上圖是殘存網絡中更新的過程, k k k是路徑的流量, 也就是所有邊容量的最小值, 然后更新所有邊的容量

E d m o n d s – K a r p Edmonds–Karp EdmondsKarp算法求最大流

時間復雜度 O ( n m 2 ) O(nm ^ 2) O(nm2)

#include <iostream>
#include <algorithm>
#include <cstring>using namespace std;const int N = 1010, M = 20010, INF = 0x3f3f3f3f;int n, m, s_node, t_node;
int head[N], edge_end[M], next_edge[M], w[M], edge_index;
int q[N], pre[N], min_val[N];
bool vis[N];void add(int ver1, int ver2, int val) {edge_end[edge_index] = ver2, next_edge[edge_index] = head[ver1], w[edge_index] = val, head[ver1] = edge_index++;
}bool bfs() {memset(vis, false, sizeof vis);int h = 0, t = -1;q[++t] = s_node;vis[s_node] = true;min_val[s_node] = INF;while (h <= t) {int u = q[h++];for (int i = head[u]; ~i; i = next_edge[i]) {int ver = edge_end[i];if (!vis[ver] && w[i]) {vis[ver] = true;min_val[ver] = min(min_val[u], w[i]);pre[ver] = i;if (ver == t_node) return true;q[++t] = ver;}}}return false;
}int edmonds_karp() {int res = 0;while (bfs()) {int val = min_val[t_node];res += val;for (int i = t_node; i != s_node; i = edge_end[pre[i] ^ 1]) {w[pre[i]] -= val;w[pre[i] ^ 1] += val;}}return res;
}int main() {ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);memset(head, -1, sizeof head);cin >> n >> m >> s_node >> t_node;while (m--) {int u, v, w;cin >> u >> v >> w;add(u, v, w);add(v, u, 0);}int res = edmonds_karp();cout << res << "\n";return 0;
}

D i n i c Dinic Dinic算法求最大流

將所有能夠增廣的路徑全部計算, 因為可能有環, 因此使用分層圖優化, 路徑只能從前一層走到后一層
分層圖 + 當前弧優化
時間復雜度 O ( n 2 m ) O(n ^ 2m) O(n2m)

在這里插入圖片描述
從起點到終點, 可以流 l i m i t limit limit的流量, 搜索從當前點開始到終點能流的流量

在這里插入圖片描述
假設在搜索到終點后流量 f i < l i m i t f_i < limit fi?<limit, 說明 f i f_i fi?一定會滿流, 那么在下一次搜索的時候不需要搜索該邊

在這里插入圖片描述
而是從下一條邊開始搜, 代碼表示為 c u r r [ u ] = i curr[u] = i curr[u]=i

#include <iostream>
#include <algorithm>
#include <cstring>using namespace std;const int N = 10010, M = 200010, INF = 0x3f3f3f3f;int n, m, s_node, e_node;
int head[N], edge_end[M], next_edge[M], w[M], edge_index;
int q[N], layer[N], curr[N];void add(int ver1, int ver2, int val) {edge_end[edge_index] = ver2, next_edge[edge_index] = head[ver1], w[edge_index] = val, head[ver1] = edge_index++;
}bool bfs() {memset(layer, -1, sizeof layer);int h = 0, t = -1;q[++t] = s_node;layer[s_node] = 0;curr[s_node] = head[s_node];while (h <= t) {int u = q[h++];for (int i = head[u]; ~i; i = next_edge[i]) {int ver = edge_end[i];if (layer[ver] == -1 && w[i]) {layer[ver] = layer[u] + 1;curr[ver] = head[ver];if (ver == e_node) return true;q[++t] = ver;}}}return false;
}int dfs(int u, int limit) {if (u == e_node) return limit;// 從當前點向后流的流量int flow = 0;for (int i = curr[u]; ~i && flow < limit; i = next_edge[i]) {int ver = edge_end[i];// i前面的邊都用完了, 當前弧更新為icurr[u] = i;if (layer[ver] == layer[u] + 1 && w[i]) {int val = dfs(ver, min(w[i], limit - flow));if (!val) layer[ver] = -1;w[i] -= val;w[i ^ 1] += val;flow += val;}}return flow;
}int dinic() {int res = 0, flow;while (bfs()) {// 搜索增廣路徑并且累計全部的流量while ((flow = dfs(s_node, INF))) {res += flow;}}return res;
}int main() {ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);memset(head, -1, sizeof head);cin >> n >> m >> s_node >> e_node;while (m--) {int u, v, w;cin >> u >> v >> w;add(u, v, w);add(v, u, 0);}int res = dinic();cout << res << "\n";return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/72865.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72865.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72865.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【css酷炫效果】純CSS實現球形陰影效果

【css酷炫效果】純CSS實現球形陰影效果 緣創作背景html結構css樣式完整代碼基礎版進階版(動態版) 效果圖 想直接拿走的老板&#xff0c;鏈接放在這里&#xff1a;上傳后更新 緣 創作隨緣&#xff0c;不定時更新。 創作背景 剛看到csdn出活動了&#xff0c;趕時間&#xff0…

Linux如何在設備樹中表示和引用設備信息

DTS基本知識 dts 硬件的相應信息都會寫在.dts為后綴的文件中&#xff0c;每一款硬件可以單獨寫一份xxxx.dts&#xff0c;一般在Linux源碼中存在大量的dts文件&#xff0c;對于arm架構可以在arch/arm/boot/dts找到相應的dts&#xff0c;一個dts文件對應一個ARM的machie。 dtsi 值…

【數學建模】模糊綜合評價模型詳解、模糊集合論簡介

模糊綜合評價模型詳解 文章目錄 模糊綜合評價模型詳解1. 模糊綜合評價模型概述2. 模糊綜合評價的基本原理2.1 基本概念2.2 評價步驟 3. 模糊綜合評價的數學模型3.1 數學表達3.2 模糊合成運算 4. 模糊綜合評價的應用領域5. 模糊綜合評價的優缺點5.1 優點5.2 缺點 6. 模糊綜合評價…

C++20 中的同步輸出流:`std::basic_osyncstream` 深入解析與應用實踐

文章目錄 一、std::basic_osyncstream 的背景與動機二、std::basic_osyncstream 的基本原理三、std::basic_osyncstream 的使用方法&#xff08;一&#xff09;基本用法&#xff08;二&#xff09;多線程環境下的使用&#xff08;三&#xff09;與文件流的結合 四、std::basic_…

C/C++藍橋杯算法真題打卡(Day8)

一、P8780 [藍橋杯 2022 省 B] 刷題統計 - 洛谷 算法代碼&#xff1a; #include<bits/stdc.h> // 包含標準庫中的所有頭文件&#xff0c;方便使用各種數據結構和算法 using namespace std; // 使用標準命名空間&#xff0c;避免每次調用標準庫函數時都要加 std::in…

JavaScript 編程:從基礎到高級應用的全面探索

引言 JavaScript 作為一種廣泛應用于 Web 開發的腳本語言&#xff0c;已經成為現代互聯網不可或缺的一部分。它不僅可以為網頁增添交互性和動態效果&#xff0c;還能在服務器端&#xff08;如 Node.js&#xff09;進行后端開發。本文將從 JavaScript 的基礎語法開始&#xff0…

第十三次CCF-CSP認證(含C++源碼)

第十三次CCF-CSP認證 跳一跳滿分題解 碰撞的小球滿分題解遇到的問題 棋局評估滿分題解 跳一跳 題目鏈接 滿分題解 沒什么好說的 基本思路就是如何用代碼翻譯題目所給的一些限制&#xff0c;以及變量應該如何更新&#xff0c;沒像往常一樣給一個n&#xff0c;怎么讀入數據&…

Pytorch使用手冊—自定義函數的雙重反向傳播與自定義函數融合卷積和批歸一化(專題五十二)

1. 使用自定義函數的雙重反向傳播 有時候,在反向計算圖中運行兩次反向傳播是有用的,例如計算高階梯度。然而,支持雙重反向傳播需要對自動求導(autograd)有一定的理解,并且需要小心處理。支持單次反向傳播的函數不一定能夠支持雙重反向傳播。在本教程中,我們將展示如何編…

MySQL:數據庫基礎

數據庫基礎 1.什么是數據庫&#xff1f;2.為什么要學習數據庫&#xff1f;3.主流的數據庫&#xff08;了解&#xff09;4.服務器&#xff0c;數據庫&#xff0c;表之間的關系5.數據的邏輯存儲6.MYSQL架構7.存儲引擎 1.什么是數據庫&#xff1f; 數據庫(Database,簡稱DB)&#x…

Web Component 教程(五):從 Lit-html 到 LitElement,簡化組件開發

前言 在現代前端開發中&#xff0c;Web 組件是一種非常流行的技術&#xff0c;它允許我們創建可重用的、自包含的 UI 元素。而 Lit-html 是一個簡潔高效庫&#xff0c;用于在 Web 組件中進行渲染。在這篇教程中&#xff0c;我們一步步學習如何 Lit-html 來創建 Web Component。…

【C++】二叉樹和堆的鏈式結構(上)

本篇博客給大家帶來的是用C語言來實現堆鏈式結構和二叉樹的實現&#xff01; &#x1f41f;&#x1f41f;文章專欄&#xff1a;數據結構 &#x1f680;&#x1f680;若有問題評論區下討論&#xff0c;我會及時回答 ??歡迎大家點贊、收藏、分享&#xff01; 今日思想&#xff…

Devops之AWS:如何安裝AWS CLI

AWS 命令行界面&#xff08;AWS CLI&#xff09;是一種開源工具&#xff0c;讓我們能夠使用命令行 Shell 中的命令與 AWS 服務進行交互。 安裝步驟&#xff1a; 下載并運行AWS CLI的MSI安裝程序&#xff1a; 點擊如下的鏈接&#xff0c;即可下載MSI安裝程序&#xff1a; htt…

PH2D數據集: 用人類演示數據提升人形機器人操作能力,助力跨實體學習

2025-03-18, 由加州大學圣地亞哥分校, 卡內基梅隆大學, 華盛頓大學, 麻省理工學院等機構聯合收集了PH2D數據集。該數據集包含26824個任務導向的人類演示&#xff0c;采用消費者級VR設備收集&#xff0c;提供了準確的3D手部關鍵點姿態和語言注釋。數據集覆蓋了多種操作任務、不同…

python 數據可視化matplotib庫安裝與使用

要使用 matplotlib 庫進行數據可視化&#xff0c;首先你需要確保已經安裝了該庫。如果你還沒有安裝&#xff0c;可以通過 Python 的包管理器 pip 來安裝它。在你的命令行工具中運行以下命令來安裝 matplotlib&#xff1a; pip install matplotlib安裝完成后&#xff0c;你就可以…

【MySQL基礎-10】MySQL中的LENGTH()函數:用法詳解與實例分析

在MySQL數據庫中&#xff0c;LENGTH()函數是一個非常常用的字符串函數&#xff0c;用于計算字符串的字節長度。理解并掌握LENGTH()函數的用法&#xff0c;對于處理字符串數據、優化查詢以及進行數據驗證都非常有幫助。本文將詳細介紹LENGTH()函數的用法&#xff0c;并通過實例演…

Matlab 基于專家pid控制的時滯系統

1、內容簡介 Matlab 185-基于專家pid控制的時滯系統 可以交流、咨詢、答疑 2、內容說明 略 在處理時滯系統&#xff08;Time Delay Systems&#xff09;時&#xff0c;使用傳統的PID控制可能會面臨挑戰&#xff0c;因為時滯會導致系統的不穩定或性能下降。專家PID控制通過結…

E902基于bash與VCS的仿真環境建立

網上看見很多E902仿真的文章&#xff0c;但用到的編譯器是類似于這種Xuantie-900-gcc-elf-newlib-x86_64-V3.0.1-20241120&#xff0c;而我按照相應的步驟與對應的編譯器&#xff0c;仿真總會報錯。后面將編譯器換成riscv64-elf-x86_64-20210512&#xff0c;反而成功了。現在開…

SpringSecurity配置(自定義認證過濾器)

文末有本篇文章的項目源碼文件可供下載學習 在這個案例中,我們已經實現了自定義登錄URI的操作,登錄成功之后,我們再次訪問后端中的API的時候要在請求頭中攜帶token,此時的token是jwt字符串,我們需要將該jwt字符串進行解析,查看解析后的User對象是否處于登錄狀態.登錄狀態下,將…

《UNIX網絡編程卷1:套接字聯網API》第1章 簡介

《UNIX網絡編程卷1&#xff1a;套接字聯網API》第1章 簡介 1.1 網絡編程的核心價值與挑戰 網絡編程是實現跨設備通信的技術基礎&#xff0c;其核心目標是通過協議棧實現數據的可靠傳輸與高效交換。在嵌入式系統、云計算、物聯網等領域&#xff0c;網絡編程能力直接決定了系統的…

D-Wave專用量子計算機登頂Science 率先展示在真實場景中的量子優勢(內附下載)

內容來源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨浪味仙 排版丨浪味仙 行業動向&#xff1a;4200字丨16分鐘閱讀 摘要&#xff1a;加拿大專用量子計算機公司 D-Wave 在 Science 期刊發表了論文&#xff0c;題為《Beyond-Classical Compu…