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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最大流,最小费用最大流:解析 + 各种板子

發布時間:2023/12/4 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最大流,最小费用最大流:解析 + 各种板子 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

網絡流初步 + Edmond-Karp算法

網絡流的基本概念

  • 源點,這個點只有流量的流出,沒有流入。
  • 匯點,這個點只有流量的流入,沒有流出。
  • 容量,每條有向邊的最大可承受的流的理論大小。
  • 流量,每條有向邊的最大可承受的流的實際大小。
  • 最大流,從源點可流入匯點的最大流量。

Edmond-Karp算法

1、如果可以找到增廣的路徑,取這條路徑上的最小的容量作為當前的可增廣的流量。

2、在這條增廣的路徑中的每一個有向邊減去當前可增廣的流量,同時在其反向邊加上當前可增廣的流量。

3、重復1的操作,如果不能找到可增廣的路徑,則說明,已經找到了最大流,輸出答案即可。

為什么要在反向邊上增加上當前可增廣的流量。

毫無疑問這張圖的最大流是4=2(1?>3?>4)+2(1?>2?>4)4 = 2(1 -> 3 -> 4) + 2(1 -> 2 -> 4)4=2(1?>3?>4)+2(1?>2?>4)

但是如果我們找尋的一條增廣路徑是2(1?>2?>3?>4)2(1 -> 2 -> 3 -> 4)2(1?>2?>3?>4)之后,我們再也就找不到其他的增廣路徑了

但是如果我們在每一次取用這條邊之后,在其反方向增加對應的反向邊。

顯然我們可以得到另一個增廣路徑2(1?>3?>2?>4)2(1 -> 3 -> 2 -> 4)2(1?>3?>2?>4),這里我們得到的最大流,也是正確答案。

板子 + 例題

Flow Problem 題目鏈接

#include <bits/stdc++.h>using namespace std;const int INF = 0x3f3f3f3f;int maze[20][20], n, m; int visit[20], pre[20];bool bfs(int st, int ed) {queue<int> q;memset(visit, 0, sizeof visit);q.push(st);visit[st] = 1;while(!q.empty()) {int temp = q.front();q.pop();if(temp == ed) return true;for(int i = 1; i <= n; i++) {if(!visit[i] && maze[temp][i] > 0) {visit[i] = 1;q.push(i);pre[i] = temp;}}}return false; }int max_flow(int st, int ed) {int ans = 0;while(bfs(st, ed)) {int now_max = INF;int p = ed;while(p != st) {now_max = min(now_max, maze[pre[p]][p]);p = pre[p];}p = ed;while(p != st) {maze[pre[p]][p] -= now_max;maze[p][pre[p]] += now_max;p = pre[p];}ans += now_max;}// cout << ans << endl;return ans; }int main() {// freopen("in.txt", "r", stdin);int t, x, y, w;scanf("%d", &t);for(int cas = 1; cas <= t; cas++) {scanf("%d %d", &n, &m);memset(maze, 0, sizeof maze);for(int i = 0; i < m; i++) {scanf("%d %d %d", &x, &y, &w);maze[x][y] += w;}printf("Case %d: %d\n", cas, max_flow(1, n));}return 0; }

最大流

Edmond-Karp

原版的是用鄰接矩陣寫的,太耗內存了,這里改成鄰接表。

#include <bits/stdc++.h>using namespace std;const int N1 = 1e4 + 10, N2 = 2e5 + 10; const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], cnt; int flow[N1], pre[N1], id[N1], n, m, s, t;void add(int x, int y, int w) {to[cnt] = y;nex[cnt] = head[x];cap[cnt] = w;head[x] = cnt++; }void input() {scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, w;for(int i = 0; i < m; i++) {scanf("%d %d %d", &x, &y, &w);add(x, y, w);add(y, x, 0);} }void init() {memset(head, -1, sizeof head);cnt = 0; }int max_flow() {int ans = 0;for(;;) {queue<int> q;memset(flow, 0, sizeof flow);flow[s] = INF;q.push(s);while(!q.empty()) {int temp = q.front();q.pop();for(int i = head[temp]; ~i; i = nex[i]) {if(!flow[to[i]] && cap[i] > 0) {flow[to[i]] = min(flow[temp], cap[i]);pre[to[i]] = temp;id[to[i]] = i;q.push(to[i]);}}if(flow[t]) break;}if(!flow[t]) break;int p = t;while(p != s) {cap[id[p]] -= flow[t];cap[id[p] ^ 1] += flow[t];p = pre[p];}ans += flow[t];}return ans; }int main() {// freopen("in.txt", "r", stdin);init();input();printf("%d\n", max_flow());return 0; }

Dinic

玄學的Dinic

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N1 = 1e4 + 10, N2 = 2e5 + 10; const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], cnt; int now[N1];int dis[N1], n, m, s, t;void init() {memset(head, -1, sizeof head);cnt = 0; }void add(int x, int y, int w) {to[cnt] = y;nex[cnt] = head[x];cap[cnt] = w;head[x] = cnt++; }bool bfs() {memset(dis, -1, sizeof dis);queue<int> q;q.push(s);dis[s] = 0;now[s] = head[s];while(!q.empty()) {int temp = q.front();q.pop();if(temp == t) return true;for(int i = head[temp]; ~i; i = nex[i]) {if(dis[to[i]] == -1 && cap[i]) {now[to[i]] = head[to[i]];dis[to[i]] = dis[temp] + 1;q.push(to[i]);}}}return false; }ll dfs(int rt, ll f) {if(rt == t) return f;ll delta = f;for(int i = now[rt]; ~i; i = nex[i]) {now[rt] = i;if(dis[to[i]] == dis[rt] + 1) {int temp = dfs(to[i], min(delta, 1ll * cap[i]));cap[i] -= temp;cap[i ^ 1] += temp;delta -= temp;}if(delta == 0) break;} return f - delta; }ll Dinic() {ll ans = 0;while(bfs()) ans += dfs(s, 0x3f3f3f3f3f3f3f3f);return ans; }int main() {// freopen("in.txt", "r", stdin);init();scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, w;for(int i = 0; i < m; i++) {scanf("%d %d %d", &x, &y, &w);add(x, y, w);add(y, x, 0);}printf("%lld\n", Dinic());return 0; }

最小費用最大流

SPFA

#include <bits/stdc++.h>using namespace std;const int N1 = 5e3 + 10, N2 = 1e5 + 10; const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], value[N2], cnt;int dis[N1], pre[N1], id[N1], flow[N1], visit[N1], n, m, s, t;void add(int x, int y, int f, int w) {to[cnt] = y;nex[cnt] = head[x];value[cnt] = w;cap[cnt] = f;head[x] = cnt++; }bool spfa() {memset(visit, 0, sizeof visit);memset(dis, 0x3f, sizeof dis);queue<int> q;q.push(s);dis[s] = 0, visit[s] = 1, flow[s] = INF, pre[t] = -1;while(!q.empty()) {int temp = q.front();q.pop();visit[temp] = 0;for(int i = head[temp]; ~i; i = nex[i]) {if(cap[i] > 0 && dis[to[i]] > dis[temp] + value[i]) {dis[to[i]] = dis[temp] + value[i];flow[to[i]] = min(flow[temp], cap[i]);pre[to[i]] = temp;id[to[i]] = i;if(!visit[to[i]]) {q.push(to[i]);visit[to[i]] = 1;}}}}return pre[t] != -1; }int min_cost_and_max_flow() {int max_flow = 0, min_cost = 0;while(spfa()) {max_flow += flow[t];min_cost += flow[t] * dis[t];int p = t;while(p != s) {cap[id[p]] -= flow[t];cap[id[p] ^ 1] += flow[t];p = pre[p];}}printf("%d %d\n", max_flow, min_cost); }void init() {memset(head, -1, sizeof head);cnt = 0; }int main() {// freopen("in.txt", "r", stdin);init();scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, f, w;for(int i = 0; i < m; i++) {scanf("%d %d %d %d", &x, &y, &f, &w);add(x, y, f, w);add(y, x, 0, -w);}min_cost_and_max_flow();return 0; }

兩個假的Dijkstra

洛谷模板題卡爆DIjkstra。

好像第一個稍優一點。

第一個假的Dijkstra

#include <bits/stdc++.h> #define mp make_pair #define pb push_back #define x first #define y secondusing namespace std;typedef pair<int, int> PII; const int N1 = 5e3 + 10; const int INF = 0x3f3f3f3f;int dis[N1], h[N1], flow[N1], pre[N1], id[N1], visit[N1], n, m, s, t;struct Edge {int to, cap, value, rever;Edge(int _to, int _cap, int _value, int _rever) : to(_to), cap(_cap), value(_value), rever(_rever) {} };vector<Edge> G[N1];void add(int x, int y, int f, int w) {Edge temp1 = Edge(y, f, w, G[y].size());Edge temp2 = Edge(x, 0, -w, G[x].size());G[x].pb(temp1);G[y].pb(temp2); }int min_cost_and_max_flow() {int min_cost = 0, max_flow = 0;memset(dis, 0x3f, sizeof dis);for(;;) {priority_queue<PII, vector<PII>, greater<PII> > q;dis[s] = 0, flow[s] = INF;q.push(mp(0, s));while(!q.empty()) {PII temp = q.top();q.pop();if(visit[temp.y]) continue;visit[temp.y] = 1;int u = temp.y;for(int i = 0; i < G[u].size(); i++) {Edge v = G[u][i];if(v.cap > 0 && dis[v.to] > dis[u] + v.value + h[u] - h[v.to]) {dis[v.to] = dis[u] + v.value + h[u] - h[v.to];flow[v.to] = min(v.cap, flow[u]);pre[v.to] = u;id[v.to] = i;q.push(mp(dis[v.to], v.to));}}}if(visit[t] == 0) break;max_flow += flow[t];for(int i = 1; i <= n; i++) {h[i] += dis[i];dis[i] = INF;visit[i] = 0;}min_cost += flow[t] * h[t];int p = t;while(p != s) {G[pre[p]][id[p]].cap -= flow[t];G[p][ G[pre[p]][id[p]].rever].cap += flow[t];p = pre[p];}}printf("%d %d\n", max_flow, min_cost); }int main() {// freopen("in.txt", "r", stdin);scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, f, w;for(int i = 0; i < m; i++) {scanf("%d %d %d %d", &x, &y, &f, &w);add(x, y, f, w);}min_cost_and_max_flow();return 0; }

第二個假的Dijkstra

#include <bits/stdc++.h> #define mp make_pairusing namespace std;typedef pair<int, int> PII; const int N1 = 5e3 + 10, N2 = 1e5 + 10; const int INF = 0x3f3f3f3f;int head[N1], to[N2], nex[N2], cap[N2], value[N2], cnt;int visit[N1], flow[N1], dis[N1], pre[N1], id[N1], h[N1], n, m, s, t;void init() {memset(head, -1, sizeof head);cnt = 0; }void add(int x, int y, int f, int w) {to[cnt] = y;nex[cnt] = head[x];value[cnt] = w;cap[cnt] = f;head[x] = cnt++; }int min_cost_and_max_flow() {int min_cost = 0, max_flow = 0;memset(dis, 0x3f, sizeof dis);for(;;) {priority_queue<PII, vector<PII>, greater<PII> > q;q.push(mp(0, s));flow[s] = INF, dis[s] = 0;while(!q.empty()) {int temp = q.top().second;q.pop();// if(temp == t) break;if(visit[temp]) continue;visit[temp] = 1;// if(temp == t) break;for(int i = head[temp]; ~i; i = nex[i]) {if(cap[i] > 0 && dis[to[i]] > dis[temp] + value[i] + h[temp] - h[to[i]]) {dis[to[i]] = dis[temp] + value[i] + h[temp] - h[to[i]];flow[to[i]] = min(flow[temp], cap[i]);pre[to[i]] = temp;id[to[i]] = i;q.push(mp(dis[to[i]], to[i]));}}}if(visit[t] == 0) break;for(int i = 1; i < n; i++) {h[i] += dis[i];visit[i] = 0;dis[i] = INF;}max_flow += flow[t];min_cost += flow[t] * h[t];int p = t;while(p != s) {cap[id[p]] -= flow[t];cap[id[p] ^ 1] += flow[t];p = pre[p];}}printf("%d %d\n", max_flow, min_cost); }int main() {// freopen("in.txt", "r", stdin);init();scanf("%d %d %d %d", &n, &m, &s, &t);int x, y, f, w;for(int i = 0; i < m; i++) {scanf("%d %d %d %d", &x, &y, &f, &w);add(x, y, f, w);add(y, x, 0, -w);}min_cost_and_max_flow();return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的最大流,最小费用最大流:解析 + 各种板子的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。