日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

网络流-最大流问题详解(C++实现)

發(fā)布時間:2023/12/20 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络流-最大流问题详解(C++实现) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一,算法背景與理論

1.1 前言

1,本文將深入探討最大流問題的dinic算法求解。
2,本文代碼通過C++實現(xiàn),不涉及算法競賽知識,代碼實現(xiàn)著重于結(jié)構(gòu)化以及功能而非性能。
3,本文關(guān)注點在最大流的實現(xiàn),而其中遇到的其他算法不會深入討論(深度優(yōu)先搜索DFS,廣度優(yōu)先搜索BFS)

1.2 基本概念介紹

在最大流問題中,網(wǎng)絡(luò)可以看成一個帶權(quán)重的有向無環(huán)圖。

  • 源點(S): 該有向圖中的一個特殊的點,只出不進(jìn),被稱作源點。
  • 匯點(T): 該有向圖中另一個特殊的點,只進(jìn)不出,被稱作匯點。
  • 容量(maxV): 記錄每條邊最大可通過的流量。
  • 流量(flow): 記錄當(dāng)前邊上通過的流量。
  • 最大流(maxFlow): 從源點出發(fā),通過重重有向邊容量的約束,最終能到達(dá)匯點的最大流量被稱作最大流。

簡單來說:就好比水廠送水,源點相當(dāng)于水廠,匯點相當(dāng)于你家,每個有向邊相當(dāng)于每條輸水管道,而容量相當(dāng)于每條輸水管道的最大容納量。于是最大流問題就可以理解成為計算同一時間你家最多能獲得多少水。

1.3 算法步驟詳解

以下圖為例:

其中節(jié)點1為源點,節(jié)點7為匯點,通過觀察上圖,我們很容易得到該圖最大流是:

1->2->7 flow:22
1->4->7 flow:10
1->5->6->7 flow:45
maxFlow = 77

那么如何通過計算機(jī)實現(xiàn)這一過程呢?

了解過算法的都應(yīng)該知道圖的遍歷可以通過深度優(yōu)先搜索的方式進(jìn)行。于是我們就可以很容易的通過深度優(yōu)先搜索從源點開始向匯點進(jìn)行搜索,并且在搜索過程中不斷更新邊的權(quán)值。為此我們引入殘量的概念。殘量: 記錄當(dāng)前邊所剩余的容量(即最大容量-當(dāng)前流量)。

當(dāng)一條邊的殘量為0,則這條邊可以看作是一條斷邊。

那么如何知曉此時匯點達(dá)到了最大流?

可以利用BFS計算每一個節(jié)點的深度,我們引入增廣路的概念。
增廣路: 能使匯點流量增大的通路。

于是最大流問題也可以理解為找增廣路的過程,當(dāng)整個圖中不在存在增廣路的時候也就說明此時匯點流量達(dá)到了最大值。
利用BFS標(biāo)記節(jié)點深度,當(dāng)匯點深度無法被標(biāo)記的時候,就說明整個圖中再也沒有能到達(dá)匯點的通路,也就是沒有增廣路。

但有的時候總會遇到預(yù)料之外的情況,如下圖:

通過圖像,我們很清楚的知道若使匯點流量最大,最優(yōu)通路應(yīng)該是:

1->2->4 flow:1
1->3->4 flow:1
maxFlow=2

可是假如當(dāng)出現(xiàn)以下情況時:

此時DFS為我們選擇了1->2->3->4這條路,但顯然不是最優(yōu)的情況,可是因為是有向圖,搜索無法回退。

如何使算法反悔?

可以通過加反邊的方式實現(xiàn)算法反悔,為每兩個連接的節(jié)點之間添加一條殘量為0的反邊。DFS經(jīng)過時使原始邊減去當(dāng)前流量的同時為反邊加上當(dāng)前流量,從而實現(xiàn)反悔。簡單來說就是當(dāng)水不想從這個管道輸送的時候,這個管道就將把水退回上一個節(jié)點。

所以整體算法思路就是BFS確定節(jié)點深度,DFS搜索更新殘量并返回此次搜索為匯點增加的流量值,然后繼續(xù)BFS確定新的節(jié)點深度,再DFS搜索更新殘量并返回此次搜索為匯點增加的流量值,直到BFS發(fā)現(xiàn)無法到達(dá)源點時,算法停止。

1.4 算法示例

以下圖為例,首先通過BFS確定每一個節(jié)點,并規(guī)定當(dāng)前節(jié)點只能由depth-1的節(jié)點擴(kuò)展得到,例如depth=2的節(jié)點,只能由depth=1的節(jié)點擴(kuò)展得到。這樣做首先是避免了大量不必要的搜索,其次是解決了加反邊后產(chǎn)生的回路造成的死循環(huán)的影響。

經(jīng)過一輪DFS后剩余的邊如下圖所示(這里省略了所有殘量為0的邊):

此時匯點流量為 32:

1->2->7 flow:22
1->4->7 flow:10

再利用BFS計算更新每個節(jié)點的深度,然后繼續(xù)通過DFS進(jìn)行搜索,得到1->5->6->7 flow:45,循環(huán)往復(fù)直到不存在增廣路,最終得到最大流為77。

二,代碼展示

代碼無非是解決以下幾個問題:
1,讀取圖信息,本文是通過讀取txt文本文件來獲取網(wǎng)絡(luò)流信息,然后在NetworkFlow.h中確定匯點與源點。

// 創(chuàng)建網(wǎng)絡(luò)圖1 2 221 4 101 5 562 3 62 4 342 7 683 4 94 6 115 6 1004 7 156 7 45

2,創(chuàng)建網(wǎng)絡(luò)流圖,本文利用結(jié)構(gòu)體作為節(jié)點數(shù)據(jù)類型,結(jié)構(gòu)體包含3個變量,分別是當(dāng)前節(jié)點深度,當(dāng)前節(jié)點存儲的數(shù)據(jù)(這個感覺寫的時候有點多此一舉),當(dāng)前節(jié)點包含的邊集,由一個鍵值對<int, int>表示,分別代表指向的節(jié)點編號以及邊的最大容量。然后利用map存儲圖所有的節(jié)點。

3,為所有節(jié)點加反邊。

4,利用BFS計算節(jié)點深度。

5,利用DFS找到增廣路,并更新殘量。,在本文的dfs函數(shù)中出現(xiàn)了三個變量,flow,rest,delta。其中flow表示當(dāng)前路線上所能承載的最大流量,rest是當(dāng)前邊的殘量,delta是該條路上將要更新的流量值。

6,繼續(xù)執(zhí)行4,5兩步直到匯點的深度為-1,即不存在增廣路是停止。

2.1 NetworkFlow.h

#pragma once#include <map>#include <vector>#include <string>#include <algorithm>#include <queue>using namespace std;#define INF 0x3F3F3F // 理論最大值#define T 7 // 匯點#define S 1 // 源點// 定義網(wǎng)絡(luò)節(jié)點typedef struct node {int data;// 存儲邊集,這里使用set數(shù)據(jù)結(jié)構(gòu)感覺會更好,加反向邊的時候會方便很多。vector<pair<int, int>> edge;int depth=-1;node(int data, vector<pair<int, int>> edge) {this->data = data;this->edge = edge;}}Node;// 初始化網(wǎng)路map<int, Node> initNetwork();// 格式化文件輸入的數(shù)據(jù)vector<int> formatInput(string str);// 加反向邊map<int, Node> addReverseEdge(map<int, Node> networkFlow);// 深度優(yōu)先搜索計算節(jié)點深度bool bfs(map<int, Node> &networkFlow);// 深度優(yōu)先搜索求增廣路int dfs(int currentNode, int flow, map<int, Node> &networkFlow);// dinic算法求最大流int dinic(map<int, Node> networkFlow);// 重置深度void resetting(map<int, Node> &networkFlow);

2.2 NetworkFlow.cpp

#include <iostream>#include <fstream>#include "NetworkFlow.h"using namespace std;// 初始化圖結(jié)構(gòu)map<int, Node> initNetwork() {map<int, Node> networkFlow;map<int, Node>::iterator iter;ifstream network("./network.txt");string str;if (!network.is_open()) {cout << "File can't open" << endl;exit(0);}while (getline(network, str)){vector<int> formatNodeInfo = formatInput(str);int prev = formatNodeInfo[0];int next = formatNodeInfo[1];int volume = formatNodeInfo[2];iter = networkFlow.find(prev);if (iter == networkFlow.end()){networkFlow.insert(pair<int, Node>(prev, Node(prev, {})));}iter = networkFlow.find(next);if (iter == networkFlow.end()) {networkFlow.insert(pair<int, Node>(next, Node(next, {})));}iter = networkFlow.find(prev);iter->second.edge.push_back(pair<int, int>(next, volume));}return networkFlow;}// 格式化輸入數(shù)據(jù)vector<int> formatInput(string str) {vector<int> formatNodeInfo;for (int i = 0; i < str.length(); i++) {string temp = "";while (str[i] != ' ' && i < str.length()) {temp = temp + str[i];i++;}formatNodeInfo.push_back(atoi(temp.c_str()));temp.clear();}return formatNodeInfo;}// 加反向邊map<int, Node> addReverseEdge(map<int, Node> networkFlow) {map<int, Node> resultNetwork = networkFlow;map<int, Node>::iterator iter;for (iter = networkFlow.begin(); iter != networkFlow.end(); iter++) {for (auto item : iter->second.edge) {int next = item.first;int volume = item.second;map<int, Node>::iterator iter_temp;iter_temp = resultNetwork.find(next);if (iter_temp != resultNetwork.end()) {iter_temp->second.edge.push_back(pair<int, int>(iter->first, 0));}else {cout << "添加反向邊錯誤,未找到指向節(jié)點" << endl;}}}return resultNetwork;}// 廣度優(yōu)先搜索求節(jié)點深度bool bfs(map<int, Node> &networkFlow) {resetting(networkFlow);queue<int> q;q.push(S);networkFlow.find(S)->second.depth = 0;map<int, Node>::iterator iter;while (!q.empty()) {int currentNode = q.front();q.pop();iter = networkFlow.find(currentNode);if (iter == networkFlow.end()) {cout << "bfs錯誤" << endl;exit(0);}else {for (auto i : iter->second.edge) {int next = i.first;int volume = i.second;map<int, Node>::iterator iter_next = networkFlow.find(next);if (volume != 0 && iter_next->second.depth == -1) {iter_next->second.depth = iter->second.depth + 1;q.push(i.first);}}}}return networkFlow.find(T)->second.depth != -1;}// 深度優(yōu)先搜索求增廣路int dfs(int currentNode, int flow, map<int, Node> &networkFlow) {if (currentNode == T) {return flow;}int rest = flow;map<int, Node>::iterator iter = networkFlow.find(currentNode);map<int, Node>::iterator iter_next;// 計算當(dāng)前節(jié)點度數(shù)int numOfEdge = iter->second.edge.size();for (int i = 0; i < numOfEdge; i++) {int nextNode = iter->second.edge[i].first;int volume = iter->second.edge[i].second;iter_next = networkFlow.find(nextNode);if (iter->second.depth+1 == iter_next->second.depth && volume != 0 && rest != 0) {int delta = dfs(iter_next->first, min(volume, rest), networkFlow);if (!delta) {iter_next->second.depth = 0;}// 更新邊的容量,正邊減,反邊加iter->second.edge[i].second -= delta;vector<pair<int, int>>::iterator iter_ve;for (iter_ve = iter_next->second.edge.begin(); iter_ve != iter_next->second.edge.end(); iter_ve++) {if (iter_ve->first == currentNode) {break;}}iter_ve->second += delta;rest -= delta;}}return flow - rest;}// dinic算法求最大流int dinic(map<int, Node> networkFlow) {int result = 0;while (bfs(networkFlow)) {result += dfs(S, INF, networkFlow);}return result;}// 重置深度void resetting(map<int, Node> &networkFlow) {map<int, Node>::iterator iter;for (iter = networkFlow.begin(); iter != networkFlow.end(); iter++) {iter->second.depth = -1;}}

總結(jié)

以上是生活随笔為你收集整理的网络流-最大流问题详解(C++实现)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产免费一区二区三区四区五区 | 在线性视频 | 精品无码人妻一区二区三区 | 亚洲天堂av线 | 日本免费一区二区三区最新 | 欧美天天影院 | 欧美激情三级 | 亚洲自拍av在线 | 影音先锋久久久久av综合网成人 | 无码一区二区三区 | 浮妇高潮喷白浆视频 | 9.1在线观看免费 | 依人久久 | 国产精品永久免费视频 | 美女洗澡无遮挡 | www.爱色av.com| 欧美熟妇久久久久 | jzzijzzij亚洲成熟少妇18 欧美www在线观看 | 国产又粗又长又硬免费视频 | 国产精品毛片久久久久久久av | 超碰狠狠操 | 成人免费xxxxx在线观看 | 美女看片 | 欧美三级自拍 | 在线a网站| 日韩国产一级 | 波多野吉衣在线视频 | 男人和女人在床的app | 91网站免费入口 | 伊人网站在线观看 | 青青久久av | 蜜臀av一区二区三区激情综合 | 国产福利一区二区三区 | 99久久网站 | 长篇乱肉合集乱500小说日本 | 一区二区三区不卡在线 | 午夜日韩福利 | 曰本三级日本三级日本三级 | 欧美久久网 | 在线亚洲不卡 | 国产精品视频久久久 | 日本不卡视频在线 | 精品视频免费 | 泰坦尼克号3小时49分的观看方法 | www.亚洲国产 | 日韩一区二区精品 | 亚洲激情社区 | 麻豆影视在线观看 | 欧美真人性野外做爰 | xxx视频在线观看 | 久久国产成人精品国产成人亚洲 | 欧美日韩国产黄色 | 日韩精品在线观看免费 | 欧美综合图区 | 天天狠狠干 | 亚洲午夜在线播放 | 免费超碰在线观看 | 日韩亚洲视频在线观看 | 精品国产视频在线 | 国产亚洲欧美精品久久久久久 | 任你操精品| 亚洲不卡视频 | 日韩人妻精品无码一区二区三区 | 极品福利视频 | 人妻少妇偷人精品久久久任期 | 免费色av| 亚洲视屏在线观看 | 国产无遮挡呻吟娇喘视频 | 97视频免费在线 | 亚洲一区二区三区在线看 | 国产一区二区不卡视频 | 国产伦精品一区二区三区四区视频 | 久久久久亚洲av成人网人人网站 | 精品国产乱码久久久久久郑州公司 | 久久久久久久久久久网站 | 国产精品自拍小视频 | 国内久久久久 | 日本免费一区二区视频 | 麻豆一区二区三区四区 | 欧美日韩一 | 国产女人18毛片水18精 | 亚洲成人h | 浓精h攵女乱爱av | 国产精品久久在线观看 | 免费三级黄 | 国产在线看一区 | 69久久夜色精品国产69 | 欧美激情在线观看一区 | 国产精品理论在线观看 | www.97超碰 | 少妇又紧又爽视频 | 亚洲第一综合 | 日韩在线视频一区 | 黑人性视频 | 九色一区 | 91直接进入| 影音先锋激情在线 | 亚洲熟妇无码爱v在线观看 九色福利 | 在线h网|