網絡流


我來透徹網絡流了。因為懶得打字參考了LNOI創始人的博客qwq。說白了就是粘

網絡流

網絡流定義

在一個有向圖上選擇一個源點,一個匯點,每一條邊上都有一個流量上限(以下稱為容量),即經過這條邊的流量不能超過這個上界,同時,除源點和匯點外,所有點的入流和出流都相等,而源點只有流出的流,匯點只有匯入的流。

這樣的圖叫做網絡流。

網絡流相關定義

  1. 源點:有\(n\)個點,有\(m\)條有向邊,有一個點很特殊,只出不進,叫做源點。

  2. 匯點:另一個點也很特殊,只進不出,叫做匯點。

  3. 容量和流量:每條有向邊上有兩個量,容量和流量,從i到j的容量通常用\(c[i,j]\)表示,流量則通常是\(f[i,j]\)
    通常可以把這些邊想象成道路,流量就是這條道路的車流量,容量就是道路可承受的最大的車流量。
    很顯然的,流量\(\leq\)容量。而對於每個不是源點和匯點的點來說,可以類比的想象成沒有存儲功能的貨物的中轉站,所有“進入”他們的流量和等於所有從他本身“出去”的流量。

  4. 最大流:把源點比作工廠的話,問題就是求從工廠最大可以發出多少貨物,是不至於超過道路的容量限制,也就是,最大流。

增廣路算法

該方法通過尋找增廣路來更新最大流,有\(EK,dinic,SAP,ISAP\)主流算法。

最常用的就是\(dinic\)

但是費用流需要用到\(EK\),所以要學會\(EK\)\(dinic\)算法;

增廣路:在圖中若經過一條從源點到匯點的路徑后,路徑上所有邊的剩余容量都\(>0\)(注意是\(>\)不是\(\geq\)),那么這條路徑被稱為增廣路。

我們通過找到增廣路來求解最大流,因為只要有增廣路,你的所求最大流就是不最大的,當無增廣路之后,最大流就求出來了讀者自證不難

dinic

#include <bits/stdc++.h>
using namespace std;

const int maxn(210), maxm(5010);

int n, m, s, t, cnt = 1, head[maxn], dep[maxn], cur[maxn];
long long ans;

struct edge{
	int x, y, z, nxt;
}e[maxm<<1];

inline void add_edge(int x, int y, int z){
	++cnt;
	e[cnt].x = x, e[cnt].y = y, e[cnt].z = z;
	e[cnt].nxt = head[x];
	head[x] = cnt;
	return;
}

bool bfs(){
	for(int i = 1; i <= n; i ++) dep[i] = 0;
	queue<int> q;
	q.push(s);
	dep[s] = 1;
	while(q.size()){
		int now = q.front();
		q.pop();
		for(int i = head[now]; i; i = e[i].nxt){
			int to = e[i].y, len = e[i].z;
			if(len and !dep[to]){
				dep[to] = dep[now] + 1;
				q.push(to);
				if(to == t) return 1;
			}
		}
	}
	return 0;
}

int dfs(int now, int num){
	if(now == t) return num;
	int res = num;
	for(int i = cur[now]; i and res; i = e[i].nxt){
		cur[now] = i;
		int to = e[i].y, len = e[i].z;
		if(len and (dep[to] == dep[now] + 1)){
			int k = dfs(to, min(res, len));
			if(!k) dep[to] = 0;
			e[i].z -= k, e[i^1].z += k, res -= k;
		}
	}
	return num-res;
}

void dinic(long long &ans){
	while(bfs()){
		for(int i = 1; i <= n; i ++) cur[i] = head[i];
		int num = 0;
		while(num = dfs(s,1<<29)) ans += num;
	}
	return;
}

signed main(){
	scanf("%d%d%d%d", &n, &m, &s, &t);
	for(int x, y, z; m; m --){
		scanf("%d%d%d", &x, &y, &z);
		add_edge(x,y,z);
		add_edge(y,x,0);
	}
	dinic(ans);
	printf("%lld", ans);
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM