經典網絡流題目模板(P3376 + P2756 + P3381 : 最大流 + 二分圖匹配 + 最小費用最大流)...

題目來源

  • P3376 【模板】網絡最大流
  • P2756 飛行員配對方案問題
  • P3381 【模板】最小費用最大流

最大流

最大流問題是網絡流的經典類型之一,用處廣泛,個人認為網絡流問題最具特點的操作就是建反向邊,這樣相當于給了反悔的機會,不斷地求增廣路的,最終得到最大流

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e6 + 3;
const int Max = 1e5 + 10;struct Edge {int to, next, flow;    //flow記錄這條邊當前的邊殘量
}edge[Max << 1];int n, m, s, t;
int head[Max], tot;
bool vis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;
}void add(int u, int v, int flow)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].next = head[u];head[u] = tot++;
}//向圖中增加一條容量為exp的邊(增廣路)
int dfs(int u,int exp)
{if (u == t) return exp;            //到達匯點,當前水量全部注入vis[u] = true;                    //表示已經到了過了for(int i = head[u] ; i != -1  ;i = edge[i].next){int v = edge[i].to;if(!vis[v] && edge[i].flow > 0){int flow = dfs(v, min(exp, edge[i].flow));if(flow > 0)            //形成了增廣路
            {edge[i].flow -= flow;edge[i ^ 1].flow += flow;return flow;}}}return 0;                        //無法形成增廣路的情況
}//求最大流
int max_flow()
{int flow = 0;while(true){memset(vis, 0, sizeof(vis));int part_flow = dfs(s, inf);if (part_flow == 0) return flow;flow += part_flow;}
}int main()
{
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){init();for (int i = 1, u, v, flow;i <= m; i++){scanf("%d%d%d", &u, &v, &flow);add(u, v, flow);add(v, u, 0);}printf("%d\n", max_flow());}return 0;
}
最簡單算法-Ford-Fulkerson
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) "["<<x<<","<<y<<"]"
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e6 + 3;
const int Max = 1e5 + 10;struct Edge {int to, next, flow;    //flow記錄這條邊當前的邊殘量
}edge[Max << 1];int n, m, s, t;
int head[Max], tot;
int dis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;
}void add(int u, int v, int flow)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].next = head[u];head[u] = tot++;
}bool bfs() //判斷圖是否連通
{queue<int>q;memset(dis, -1, sizeof(dis));dis[s] = 0;q.push(s);while (!q.empty()){int u = q.front();q.pop();for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (dis[v] == -1 && edge[i].flow > 0)        //可以借助邊i到達新的結點
            {dis[v] = dis[u] + 1;                    //求頂點到源點的距離編號
                q.push(v);}}}return dis[t] != -1;                                //確認是否連通
}int dfs(int u, int flow_in)
{if (u == t) return flow_in;int flow_out = 0;                                    //記錄這一點實際流出的流量for (int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if (dis[v] == dis[u] + 1 && edge[i].flow > 0){int flow_part = dfs(v, min(flow_in, edge[i].flow));if (flow_part == 0)continue;                //無法形成增廣路flow_in -= flow_part;                        //流出了一部分,剩余可分配流入就減少了flow_out += flow_part;                        //記錄這一點最大的流出
edge[i].flow -= flow_part;edge[i ^ 1].flow += flow_part;                //減少增廣路上邊的容量,增加其反向邊的容量if (flow_in == 0)break;}}return flow_out;
}int max_flow()
{int sum = 0;while (bfs()){sum += dfs(s, inf);}return sum;
}int main() {
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){init();for (int i = 1, u, v, flow;i <= m; i++){scanf("%d%d%d", &u, &v, &flow);add(u, v, flow);add(v, u, 0);}printf("%d\n", max_flow());}return 0;
}
常用且高效的算法-Dinic

?二分圖匹配

要解決這類問題,我們需要先了解什么是二分圖?

二分圖:一個圖中的所有頂點可以分為兩個集合 V,K ,其實兩個集合內部的點彼此之間無邊,如下圖所示:(藍色的點和紅色的點分屬于兩個集合V,K)

然后我們回到這個題目上來,這個題目求的是最大可出戰人數,實際上就是在二分圖中找到兩個集合中的最大匹配數,這類問題我們稱之為二分圖最大匹配數問題

屬于網絡流經典題目之一,下面說明一下建圖的過程

1)由源點向集合V中每個點建一條容量為1的邊

2)對于V,K集合之間存在的邊e,v 為V中的點,k為K中的點,我們建一條容量為1的邊,方向為 v --> k?

3)由K中每個點向匯點建一條容量為1的邊

當我們將圖建好了后,我們求這個圖的最大流,這個最大流即為二分圖最大匹配數,下面展示一下建成的圖:(S代表源點,T代表匯點,藍色的邊代表容量為1的邊)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e6 + 3;
const int Max = 1e6 + 10;struct Edge
{int to, next, flow;
}edge[Max << 1];;int n, m, a, b, s, t;
int head[Max], tot;
int dis[Max];
int ans;
bool vis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;ans = 0;
}void add(int u, int v, int flow)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].next = head[u];head[u] = tot++;
}bool bfs()
{memset(dis, -1, sizeof(dis));dis[s] = 0;queue<int>q;q.push(s);while (!q.empty()){int u = q.front();q.pop();for (int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if (dis[v] == -1 && edge[i].flow > 0){dis[v] = dis[u] + 1;if (v == t) return true;q.push(v);}}}return false;
}int dfs(int u, int flow_in)
{if (u == t) return flow_in;int flow_out = 0;for (int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if (dis[v] == dis[u] + 1 && edge[i].flow > 0){int flow_part = dfs(v, min(flow_in, edge[i].flow));if (flow_part == 0) continue;flow_in -= flow_part;flow_out += flow_part;edge[i].flow -= flow_part;edge[i ^ 1].flow += flow_part;if (flow_in == 0)break;}}return flow_out;
}int max_val()
{int sum = 0;while (bfs()){sum += dfs(s, inf);}return sum;
}int main()
{
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d", &m, &n) != EOF){init();s = 0, t = n + 1;for (int i = 1;i <= m;i++){add(s, i, 1);add(i, s, 0);    //由源點向外籍飛行員建邊
        }for (int i = m + 1; i <= n;i++){add(i, t, 1);add(t, i, 0);}while (scanf("%d%d", &a, &b) != EOF && a != -1 && b != -1){add(a, b, 1);add(b, a, 0);}printf("%d\n", max_val());for (int u = 1;u <= m;u++){for (int i = head[u]; i != -1;i = edge[i].next){if (edge[i].flow == 0 && edge[i].to != s && edge[i].to != t){printf("%d %d\n", u, edge[i].to);}}}}return 0;
}
飛行員配對方案-Dinic

?最小費用最大流

這類題目相比于最大流問題新增了每天邊單位流量的價格,問在最大流的情況下求出最小的費用。

這類題目和最大流很想,不過也有不小區別,對于這類問題,我們為每條邊建的反邊的價格是每天邊的相反數,如圖

然后我們的算法也不再是Dinic算法了,而是用spfa或者dijkstra

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const int Max = 5e3 + 10;struct Edge
{int to, rev;                    //rev記錄反向邊int flow, cost;;
};int n, m, k;
vector<Edge>edge[Max << 1];
int h[Max];                            //每個結點的勢
int dis[Max];
int pre_node[Max], pre_edge[Max];    //前驅結點和對應邊void add(int u, int v, int flow, int cost)
{edge[u].push_back({ v,(int)edge[v].size(),flow,cost });edge[v].push_back({ u,(int)edge[u].size() - 1,0,-cost });
}void min_cost_flow(int s, int t, int& min_cost, int& max_flow)
{fill(h + 1, h + 1 + n, 0);min_cost = max_flow = 0;int tot = inf;                            //源點流量無限while (tot > 0){priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > >q;memset(dis, inf, sizeof(dis));dis[s] = 0;q.push({ 0,s });while (!q.empty()){int u = q.top().second;int dist = q.top().first;q.pop();if (dis[u] < dist)continue;        //當前的距離不是最近距離for (int i = 0;i < edge[u].size(); i++){Edge &e = edge[u][i];if (edge[u][i].flow > 0 && dis[e.to] > dis[u] + e.cost + h[u] - h[e.to]){dis[e.to] = dis[u] +e.cost + h[u] - h[e.to];pre_node[e.to] = u;pre_edge[e.to] = i;q.push({ dis[e.to],e.to });}}}if (dis[t] == inf)break;            //無法增廣了,就是找到答案了for (int i = 1;i <= n;i++) h[i] += dis[i];int flow = tot;                        //求這一增廣路徑的流量for (int i = t; i != s; i = pre_node[i])flow = min(flow, edge[pre_node[i]][pre_edge[i]].flow);for (int i = t; i != s; i = pre_node[i]){Edge& e = edge[pre_node[i]][pre_edge[i]];e.flow -= flow;edge[i][e.rev].flow += flow;}tot -= flow;max_flow += flow;min_cost += flow * h[t];}
}int main()
{
#ifdef LOCAL//freopen("input.txt", "r", stdin);//freopen("output.txt", "w", stdout);
#endifint s, t;while (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){for (int i = 1, u, v, flow, cost;i <= m;i++){scanf("%d%d%d%d", &u, &v, &flow, &cost);add(u, v, flow, cost);}int min_cost, max_flow;min_cost_flow(s, t, min_cost, max_flow);printf("%d %d\n", max_flow, min_cost);}return 0;
}
無負環圖中可用的算法-dijkstra(這里給出的是可以適用于有負環的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const int Max = 1e5 + 10;struct Edge
{int to, next;int flow, cost;
}edge[Max << 1];int n, m, s, t;
int head[Max], tot;
int dis[Max];
int pre[Max];            //記錄增廣路徑此點的前一天邊
bool vis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;
}void add(int u, int v, int flow, int cost)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].cost = cost;edge[tot].next = head[u];head[u] = tot++;edge[tot].to = u;edge[tot].flow = 0;edge[tot].cost = -cost;edge[tot].next = head[v];head[v] = tot++;
}bool spfa(int s, int t)
{memset(dis, inf, sizeof(dis));memset(vis, 0, sizeof(vis));memset(pre, -1, sizeof(pre));queue<int>q;q.push(s);dis[s] = 0;vis[s] = true;while (!q.empty()){int u = q.front();q.pop();vis[u] = false;for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (edge[i].flow > 0 && dis[v] > dis[u] + edge[i].cost){dis[v] = dis[u] + edge[i].cost;pre[v] = i;if (!vis[v]){vis[v] = true;q.push(v);}}}}return pre[t] != -1;
}void min_cost_max_flow(int s, int t, int& max_flow, int& min_cost)
{max_flow = 0;min_cost = 0;while (spfa(s, t)){int flow = inf;for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])    //沿增廣路回溯edge[i^1]即為其反邊
        {flow = min(flow, edge[i].flow);}for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]){edge[i].flow -= flow;edge[i ^ 1].flow += flow;min_cost += flow * edge[i].cost;}max_flow += flow;}
}int main()
{
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){init();for (int i = 1, u, v, flow, cost;i <= m;i++){scanf("%d%d%d%d", &u, &v, &flow, &cost);add(u, v, flow, cost);}int max_flow = 0, min_cost = 0;min_cost_max_flow(s, t, max_flow, min_cost);printf("%d %d\n", max_flow, min_cost);}return 0;
}
常用且比較高效的算法-spfa

?

轉載于:https://www.cnblogs.com/winter-bamboo/p/11330082.html

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

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

相關文章

Tensorflow筆記(基礎): 圖與會話,變量

圖與會話 import tensorflow as tf import os# 取消打印 cpu,gpu選擇等的各種警告 # 設置TF_CPP_MIN_LOG_LEVEL 的等級,1.1.0以后設置2后 只不顯示警告,之前需要設置3,但設置3不利于調試 os.environ[TF_CPP_MIN_LOG_LEVEL] 2 import time# 創建一個常量 op, 產生一個 1x2 矩陣…

css左右布局代碼_如何使用CSS位置來布局網站(帶有示例代碼)

css左右布局代碼Using CSS position to layout elements on your website can be hard to figure out. What’s the difference between absolute, relative, fixed, and sticky? It can get confusing pretty quickly.使用CSS位置來布局網站上的元素可能很困難。 絕對&#x…

redis memcached MongoDB

我們現在使用的模式是&#xff0c;對于直接的key value對需緩存的直接用memcached。對于collection類型就使用Redis。對于大數據量的內容性的東西&#xff0c;我們打算嘗試用mongoDB。也正在學習neo4j&#xff0c;來應對深度搜索&#xff0c;推薦功能。 1.Memcached單個key-val…

線性代數-矩陣-轉置 C和C++的實現

原理解析&#xff1a; 本節介紹矩陣的轉置。矩陣的轉置即將矩陣的行和列元素調換&#xff0c;即原來第二行第一列&#xff08;用C21表示&#xff0c;后同&#xff09;與第一行第二列&#xff08;C12&#xff09;元素調換位置&#xff0c;原來c31與C13調換。即cij與cji調換 。 &…

數字經濟的核心是對大數據_大數據崛起為數字世界的核心潤滑劑

數字經濟的核心是對大數據“Information is the oil of the 21st century, and analytics is the combustion engine”.“信息是21世紀的石油&#xff0c;分析是內燃機”。 — Peter Sondergaard, Senior Vice President of Gartner Research.— Gartner研究部高級副總裁Peter…

乞力馬扎羅山 海明威_我如何對海明威編輯器(一種流行的寫作應用程序)進行反向工程,并從泰國的海灘上構建了自己的數據庫

乞力馬扎羅山 海明威I’ve been using the Hemingway App to try to improve my posts. At the same time I’ve been trying to find ideas for small projects. I came up with the idea of integrating a Hemingway style editor into a markdown editor. So I needed to fi…

leetcode 566. 重塑矩陣

在MATLAB中&#xff0c;有一個非常有用的函數 reshape&#xff0c;它可以將一個矩陣重塑為另一個大小不同的新矩陣&#xff0c;但保留其原始數據。 給出一個由二維數組表示的矩陣&#xff0c;以及兩個正整數r和c&#xff0c;分別表示想要的重構的矩陣的行數和列數。 重構后的…

制作簡單的WIFI干擾器

原教程鏈接:http://www.freebuf.com/geek/133161.htmlgithub 1.準備材料 制作需要的材料有 nodemcu開發版IIC通信 128*64 OLED液晶屏電線按鈕開關萬能板排針(自選)雙面膠(自選)參考2.準備焊接 引腳焊接參考 oled按鈕效果3.刷入固件 下載燒錄工具:ESP8266Flasher.exe 下載固件:…

Snipaste截圖

繪圖繪色&#xff0c;描述加圖片能更加說明問題的本質。今天推薦一款多功能的截圖snipaste... 欣賞繪色 常見報錯 解決方案&#xff1a; 下載相關的DLL即可解決&#xff0c; 請根據你操作系統的版本&#xff08;32位/64位&#xff09;&#xff0c;下載并安裝相應的微軟 Visual …

azure第一個月_MLOps:兩個Azure管道的故事

azure第一個月Luuk van der Velden and Rik Jongerius盧克范德費爾登(Luuk van der Velden)和里克 瓊格里烏斯( Rik Jongerius) 目標 (Goal) MLOps seeks to deliver fresh and reliable AI products through continuous integration, continuous training and continuous del…

firebase auth_如何使用auth和實時數據庫構建Firebase Angular應用

firebase authby Zdravko Kolev通過Zdravko Kolev 如何使用auth和實時數據庫構建Firebase Angular應用 (How to build a Firebase Angular app with auth and a real-time database) For a long time, I was looking for a good Portfolio web app that can help me to easily…

Mybatis—多表查詢

Mybatis多表查詢 一對一查詢 一對一查詢的模型MapperScannerConfigurer 用戶表和訂單表的關系為&#xff0c;一個用戶有多個訂單&#xff0c;一個訂單只從屬于一個用戶 創建Order和User實體 public class Order {private int id;private Date ordertime;private double to…

VS2008 開發設計MOSS工作流 URN 注意了

最近學習MOSS 很苦惱&#xff0c;進度也很慢&#xff0c;最近在學習VS2008開發工作流&#xff0c;其中有結合INFOPATH 2007來做, 出現個BUG或者說是設置的問題,整整花了我一天工作時間&#xff0c;是這樣的: 在部署的時候關于URN&#xff0c;大部分的教程都是這樣的說的&#…

ArangoDB Foxx service 使用

備注&#xff1a;項目使用的是github https://github.com/arangodb-foxx/demo-hello-foxx1. git clonegit clone https://github.com/arangodb-foxx/demo-hello-foxx.git 2. 安裝foxx servicefoxx-manager install demo-hello-foxx /demoapp 3. 效果自動生成的swagger 文檔項目…

編譯原理 數據流方程_數據科學中最可悲的方程式

編譯原理 數據流方程重點 (Top highlight)Prepare a box of tissues! I’m about to drop a truth bomb about statistics and data science that’ll bring tears to your eyes.準備一盒紙巾&#xff01; 我將投放一本關于統計和數據科學的真相炸彈&#xff0c;這會讓您眼淚汪…

@ConTrollerAdvice的使用

ConTrollerAdvice&#xff0c;從名字上面看是控制器增強的意思。 在javaDoc寫到/*** Indicates the annotated class assists a "Controller".** <p>Serves as a specialization of {link Component Component}, allowing for* implementation classes to be a…

Mybatis—注解開發

Mybatis的注解開發 MyBatis的常用注解 這幾年來注解開發越來越流行&#xff0c;Mybatis也可以使用注解開發方式&#xff0c;這樣我們就可以減少編寫Mapper映射文件了。 Insert&#xff1a;實現新增 Update&#xff1a;實現更新 Delete&#xff1a;實現刪除 Select&#x…

道路工程結構計算軟件_我從軟件工程到產品管理的道路

道路工程結構計算軟件by Sari Harrison莎莉哈里森(Sari Harrison) 我從軟件工程到產品管理的道路 (My path from software engineering to product management) 以及一些有關如何自己做的建議 (And some advice on how to do it yourself) I am often asked how to make the m…

Vue 指令

下面列舉VUE的HTML頁面模板指令&#xff0c;并進行分別練習。 1. templates 2. v-if, v-for <div idapp><ol><li v-for"todo in todos>{{ todo.text}}</li></ol> </div><script>app new Vue({ el: #app, data: { return…

iOS-FMDB

2019獨角獸企業重金招聘Python工程師標準>>> #import <Foundation/Foundation.h> #import <FMDatabase.h> #import "MyModel.h"interface FMDBManager : NSObject {FMDatabase *_dataBase; }(instancetype)shareInstance;- (BOOL)insert:(MyM…