网络最大流

这篇文章展示了三种求解网络最大流问题的算法:Edmonds-Karp增广路算法、未经优化的Dinic算法以及前向弧优化后的Dinic算法。每种算法都基于C++实现,包括寻找增广路、流量更新和路径搜索等关键步骤。
摘要由CSDN通过智能技术生成

P3376 【模板】网络最大流
Edmonds−Karp增广路算法

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


inline int read(int& x) {
	char ch = getchar();
	int f = 1; x = 0;
	while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0'; ch = getchar(); }
	return x * f;
}
//void ReadFile() {
//	FILE* stream1;
//	freopen_s(&stream1,"in.txt", "r", stdin);
//	freopen_s(&stream1,"out.txt", "w", stdout);
//}

static auto speedup = []() {ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return nullptr; }();



#define HEAD(input) cf.head[input]
#define NEXT(input) cf.tail[input].nx
#define VALUE(input) cf.tail[input].v
#define TO(input) cf.tail[input].to

class ChainForward {
	struct ChainForwardNode {
		ChainForwardNode() :to(0), nx(0), v(0) {}
		int to,nx;
		long long v;
	};
public:
	ChainForward(int headLen, int edgeLen) {
		init(headLen, edgeLen);
	}
	void init(int headLen, int edgeLen) {
		head.assign(headLen, 0);
		tail.assign(edgeLen, {});
		tot = 1;
	}
	int add(int from,int to,int val) {
		tail[++tot].to = to;
		tail[tot].v = val;
		tail[tot].nx = head[from];
		head[from] = tot;
		return tot;
	}
	int tot;
	vector<int> head;
	vector<ChainForwardNode> tail;
};

ChainForward cf(1000,10000);

const int maxn = 207,maxm = 1e4 + 7,INF = 1e9 + 7;
long long n, m, s, t,id[maxn][maxn],pre[maxm],vis[maxn],dis[maxn],ans = 0;

//找增广路
bool bfs() {
	memset(vis, 0, sizeof(vis));
	queue<int> q;
	q.push(s);
	vis[s] = 1;
	dis[s] = INF;

	while (!q.empty()) {
		int from = q.front(); q.pop();
		for (int i = HEAD(from); i; i = NEXT(i)) {
			if (VALUE(i) <= 0)continue;
			int to = TO(i);
			if (vis[to])continue;
			dis[to] = min(dis[from], VALUE(i));
			//记录路径
			pre[to] = i;
			vis[to] = 1;
			if (to == t)return true;
			q.push(to);
		}
	}
	return false;
}

void update() {
	//增广路流量
	int x = t,flow = dis[t];
	while (x != s) {
		int v = pre[x];
		//去掉增广路
		VALUE(v) -= flow;
		//增加反向边
		VALUE(v ^ 1) += flow;
		//回退
		x = TO(v ^ 1);
	}
	ans += flow;
}

void slove() {
	cin >> n >> m >> s >> t;
	int a, b, c;
	for (int i = 1; i <= m; i++) {
		cin >> a >> b >> c;
		if (id[a][b] == 0) {
			int idx = cf.add(a, b, c);
			cf.add(b, a, 0);
			id[a][b] = idx;
		}
		else {
			int idx = id[a][b];
			VALUE(idx) += c;
		}
	}

	while (bfs()) {
		update();
	}
	cout << ans << endl;
}
int main() {
	slove();
	return 0;
}

Edmonds−Karp增广路算法

class NetFlowBase{
public:
	typedef long long T;
	struct Edge{
		int to,nx;
		T flow;
		Edge(int _to,T _flow,int _nx):to(_to),flow(_flow),nx(_nx){}
	};
	void Init(int n){
		head.assign(n + 1,-1);
	}
	int Add(int from,int to,T flow){
		int ret = tail.size();
		Edge e(to,flow,head[from]);
		head[from] = tail.size();
		tail.push_back(e);
		return ret;
	}
	int Head(int cur){return head[cur];}
	int Next(int cur){return tail[cur].nx;}
	T &Value(int cur){return tail[cur].flow;}
	int &To(int cur){return tail[cur].to;}

	vector<Edge> tail;
	vector<int> head;
};

class EK:public NetFlowBase{
public:
	static const int INF = 1e9;
	EK(int _n,int _s,int _t){
		n = _n;
		vis.assign(n + 1,0);
		dis.assign(n + 1,0);
		pre.assign(n + 1,0);
		s = _s;
		t = _t;
		Init(n);
	}

	bool bfs(){
		fill(vis.begin(),vis.end(),0);
		queue<int> q;
		q.push(s);
		vis[s] = 1;
		dis[s] = INF;

		while (!q.empty()) {
			int from = q.front(); q.pop();
			for (int i = Head(from); ~i; i = Next(i)) {
				if (Value(i) <= 0)continue;
				int to = To(i);
				if (vis[to])continue;
				dis[to] = min(dis[from], Value(i));
				//记录路径
				pre[to] = i;
				vis[to] = 1;
				if (to == t)return true;
				q.push(to);
			}
		}
		return false;
	}
	T update(){
		//增广路流量
		T flow = dis[t],ans = 0;
		int x = t;
		while (x != s) {
			int v = pre[x];
			//去掉增广路
			Value(v) -= flow;
			//增加反向边
			Value(v ^ 1) += flow;
			//回退
			x = To(v ^ 1);
		}
		ans += flow;
		return ans;
	}

	T GetMaxFlow(){
		T ans = 0;
		while (bfs()) {
			ans += update();
		}
		return ans;
	}
	vector<bool> vis;
	vector<int> pre;
	vector<T> dis;
	int s,t,n;
};


const int maxn = 207;
int id[maxn][maxn];

void slove() {
	int n,m,s,t;
	cin >> n >> m >> s >> t;
	int a, b, c;

	EK ek(n,s,t);
	for (int i = 1; i <= m; i++) {
		cin >> a >> b >> c;
		if (id[a][b] == 0) {
			int idx = ek.Add(a, b, c);
			ek.Add(b, a, 0);
			id[a][b] = idx;
		}
		else {
			int idx = id[a][b];
			ek.Value(idx) += c;
		}
	}

	cout << ek.GetMaxFlow() << endl;
}
int main() {
	slove();
	return 0;
}

vector写法

class NetFlow {
public:
	typedef long long T;
	struct Edge {
		int to, id;
		T flow;
		Edge(int _to, T _flow, int _id) :to(_to), flow(_flow),id(_id) {}
	};
	NetFlow(int _n,int _s,int _t) {
		e.assign(_n + 1, {});
	}
	void Add(int from,int to, T flow) {
		int alen = e[from].size();
		int blen = e[to].size();
		e[from].push_back(Edge(to,flow,blen));
		e[to].push_back({from,0,alen });
	}
	T &Value(Edge& edge) {
		return edge.flow;
	}
	int To(Edge& edge) {
		return edge.to;
	}
	int Pre(Edge& edge) {
		return edge.id;
	}
	vector<vector<Edge> > e;
};

class EK :public NetFlow {
public:
	static constexpr T INF = 1e15;
	EK(int _n, int _s, int _t):NetFlow(_n,_s,_t) {
		s = _s;t = _t;n = _n;
		vis.assign(n + 1, false); last.assign(n + 1, 0); pre.assign(n + 1, 0); dis.assign(n + 1, 0);
	}
	bool bfs() {
		fill(vis.begin(), vis.end(), false);
		queue<int> q;
		q.push(s);
		dis[s] = INF; vis[s] = true;
		while (!q.empty()) {
			int x = q.front(); q.pop();
			for (int i = 0; i < e[x].size(); i++) {
				Edge& edge = e[x][i];
				int cur = To(edge);
				if (Value(edge) <= 0 || vis[cur]) continue;
				vis[cur] = true;
				dis[cur] = min(dis[x], Value(edge));
				pre[cur] = i;
				last[cur] = x;
				if (cur == t) return true;
				q.push(cur);
			}
		}
		return false;
	}
	T update() {
		//增广路流量
		T flow = dis[t], ans = 0;
		int x = t;
		while (x != s) {
			int a = last[x];
			int b = pre[x];
			Edge& edge = e[a][b];
			//去掉增广路
			Value(edge) -= flow;
			//增加反向边
			Edge& revEdge = e[x][Pre(edge)];
			Value(revEdge) += flow;
			//回退
			x = last[x];
		}
		ans += flow;
		return ans;
	}
	T GetMaxFlow() {
		T ans = 0;
		while (bfs()) {
			ans += update();
		}
		return ans;
	}
	int s, t,n;
	vector<bool> vis;
	vector<int> pre,last;
	vector<T> dis;
};

//dinic

class Dinic :public NetFlow {
public:
	static constexpr T INF = 1e15;
	Dinic(int _n, int _s, int _t) :NetFlow(_n, _s, _t) {
		s = _s; t = _t; n = _n;
		dep.assign(n + 1, 0); arc.assign(n + 1, 0);
	}

	bool bfs() {
		queue<int> q;
		q.push(s);
		fill(dep.begin(), dep.end(), -1);
		dep[s] = 0;

		while (!q.empty()) {
			int from = q.front(); q.pop();
			for (auto& edge : e[from]) {
				int cur = To(edge);
				if (dep[cur] != -1 || Value(edge) <= 0) continue;
				dep[cur] = dep[from] + 1;
				q.push(cur);
			}
		}
		fill(arc.begin(), arc.end(), 0);
		return dep[t] != -1;
	}
	T dfs(int x, long long sum) {
		if (x == t) return sum;

		T flow = 0;
		for (int i = arc[x]; i < e[x].size(); i++) {
			Edge& edge = e[x][i];
			arc[x] = i;
			int cur = To(edge);
			if (Value(edge) > 0 && dep[cur] == dep[x] + 1) {
				if (flow = dfs(cur, min(sum, Value(edge)) ) ) {
					Value(edge) -= flow;
					Edge& PreEdge = e[cur][Pre(edge)];
					Value(PreEdge) += flow;
					return flow;
				}
				else dep[cur] = -1;
			}
		}
		return flow;
	}
	T GetMaxFlow() {
		int flow = 0;
		T ans = 0;
		while (bfs()) {
			while (flow = dfs(s, INF))ans += flow;
		}
		return ans;
	}
	vector<int> dep,arc;
	int s, n, t;
};

//ISAP

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


inline long long read() {
	char ch = getchar();
	long long f = 1,x = 0;
	while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0'; ch = getchar(); }
	return x * f;
}
//void ReadFile() {
//	FILE* stream1;
//	freopen_s(&stream1,"in.txt", "r", stdin);
//	freopen_s(&stream1,"out.txt", "w", stdout);
//}

static auto speedup = []() {ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return nullptr; }();

#define HEAD(input) cf.head[input]
#define NEXT(input) cf.tail[input].nx
#define VALUE(input) cf.tail[input].v
#define TO(input) cf.tail[input].to
#define ADD(a,b,c) cf.add(a,b,c)

class ChainForward {
	struct ChainForwardNode {
		ChainForwardNode() :to(0), nx(0), v(0) {}
		int to,nx;
		long long v;
	};
public:
	ChainForward(int headLen, int edgeLen) {
		init(headLen, edgeLen);
	}
	void init(int headLen, int edgeLen) {
		head.assign(headLen, 0);
		tail.assign(edgeLen, {});
		tot = 1;
	}
	int add(int from,int to,long long val) {
		tail[++tot].to = to;
		tail[tot].v = val;
		tail[tot].nx = head[from];
		head[from] = tot;
		return tot;
	}
	int tot;
	vector<int> head;
	vector<ChainForwardNode> tail;
};

ChainForward cf(2000, 5e5 + 7);

const int maxn = 2e3;
const long long INF = 1e15 + 7;
int dep[maxn], gap[maxn],id[maxn][maxn];
long long n, m, s, t,ans = 0;

void bfs() {
	memset(dep, -1, sizeof(dep));
	memset(gap, 0, sizeof(gap));

	queue<int> q;
	q.push(t);
	dep[t] = 0;
	gap[0] = 1;


	while (!q.empty()) {
		int from = q.front();
		q.pop();
		for (int i = HEAD(from); i; i = NEXT(i)) {
			int to = TO(i);
			if (dep[to] == -1) {
				dep[to] = dep[from] + 1;
				gap[dep[to]]++;
				q.push(to);
			}
		}
	}
	return;
}
long long  dfs(int x, long long  flow) {
	if (x == t) return flow;

	long long  used = 0;
	for (int i = HEAD(x); i; i = NEXT(i)) {
		int to = TO(i);
		if (VALUE(i) && dep[to] + 1 == dep[x]) {
			long long ret = dfs(to, min(flow - used, VALUE(i)));
			if (ret) {
				VALUE(i) -= ret;
				VALUE(i ^ 1) += ret;
				used += ret;
			}
			if (used == flow) return used;
		}
	}

	--gap[dep[x]];

	if (gap[dep[x]] == 0) {
		dep[s] = n + 1;
	}
	dep[x]++;
	gap[dep[x]]++;
	return used;
}
void ISAP() {
	ans = 0;
	bfs();
	while (dep[s] < n) {
		ans += dfs(s, INF);
	}
	printf("%lld\n", ans);
	//cout << ans << endl;
}
signed main() {
	n = read(), m = read(), s = read(), t = read();
	//cin >> n >> m >> s >> t;
	for (int i = 1; i <= m; i++) {
		int a, b, c;
		//cin >> a >> b >> c;
		a = read(), b = read(), c = read();
		if (id[a][b] == 0) {
			id[a][b] = ADD(a, b, c);
			ADD(b, a, 0);
		}
		else {
			VALUE(id[a][b]) += c;
		}

	}
	ISAP();
	return 0;
}

HLPP

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


inline long long read() {
	char ch = getchar();
	long long f = 1,x = 0;
	while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0'; ch = getchar(); }
	return x * f;
}
//void ReadFile() {
//	FILE* stream1;
//	freopen_s(&stream1,"in.txt", "r", stdin);
//	freopen_s(&stream1,"out.txt", "w", stdout);
//}

static auto speedup = []() {ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return nullptr; }();


const int N = 2000, M = 150000, INF = 0x3f3f3f3f;
int n, m, s, t;

struct qxx {
    int nex, t;
    long long v;
};

qxx e[M * 2 + 1];
int h[N + 1], cnt = 1;

void add_path(int f, int t, long long v) {
    e[++cnt] = qxx{ h[f], t, v }, h[f] = cnt;
}

void add_flow(int f, int t, long long v) {
    add_path(f, t, v);
    add_path(t, f, 0);
}

int ht[N + 1];        // 高度;
long long ex[N + 1];  // 超额流;
int gap[N];           // gap 优化. gap[i] 为高度为 i 的节点的数量
stack<int> B[N];      // 桶 B[i] 中记录所有 ht[v]==i 的v
int level = 0;        // 溢出节点的最高高度

int push(int u) {      // 尽可能通过能够推送的边推送超额流
    bool init = u == s;  // 是否在初始化
    for (int i = h[u]; i; i = e[i].nex) {
        const int& v = e[i].t;
        const long long& w = e[i].v;
        // 初始化时不考虑高度差为1
        if (!w || (init == false && ht[u] != ht[v] + 1) || ht[v] == INF) continue;
        long long k = init ? w : min(w, ex[u]);
        // 取到剩余容量和超额流的最小值,初始化时可以使源的溢出量为负数。
        if (v != s && v != t && !ex[v]) B[ht[v]].push(v), level = max(level, ht[v]);
        ex[u] -= k, ex[v] += k, e[i].v -= k, e[i ^ 1].v += k;  // push
        if (!ex[u]) return 0;  // 如果已经推送完就返回
    }
    return 1;
}

void relabel(int u) {  // 重贴标签(高度)
    ht[u] = INF;
    for (int i = h[u]; i; i = e[i].nex)
        if (e[i].v) ht[u] = min(ht[u], ht[e[i].t]);
    if (++ht[u] < n) {  // 只处理高度小于 n 的节点
        B[ht[u]].push(u);
        level = max(level, ht[u]);
        ++gap[ht[u]];  // 新的高度,更新 gap
    }
}

bool bfs_init() {
    memset(ht, 0x3f, sizeof(ht));
    queue<int> q;
    q.push(t), ht[t] = 0;
    while (q.size()) {  // 反向 BFS, 遇到没有访问过的结点就入队
        int u = q.front();
        q.pop();
        for (int i = h[u]; i; i = e[i].nex) {
            const int& v = e[i].t;
            if (e[i ^ 1].v && ht[v] > ht[u] + 1) ht[v] = ht[u] + 1, q.push(v);
        }
    }
    return ht[s] != INF;  // 如果图不连通,返回 0
}

// 选出当前高度最大的节点之一, 如果已经没有溢出节点返回 0
int select() {
    while (B[level].size() == 0 && level > -1) level--;
    return level == -1 ? 0 : B[level].top();
}

long long hlpp() {            // 返回最大流
    if (!bfs_init()) return 0;  // 图不连通
    memset(gap, 0, sizeof(gap));
    for (int i = 1; i <= n; i++)
        if (ht[i] != INF) gap[ht[i]]++;  // 初始化 gap
    ht[s] = n;
    push(s);  // 初始化预流
    int u;
    while ((u = select())) {
        B[level].pop();
        if (push(u)) {  // 仍然溢出
            if (!--gap[ht[u]])
                for (int i = 1; i <= n; i++)
                    if (i != s && ht[i] > ht[u] && ht[i] < n + 1)
                        ht[i] = n + 1;  // 这里重贴成 n+1 的节点都不是溢出节点
            relabel(u);
        }
    }
    return ex[t];
}

int main() {
    scanf_s("%d%d%d%d", &n, &m, &s, &t);
    for (int i = 1, u, v, w; i <= m; i++) {
        scanf_s("%d%d%d", &u, &v, &w);
        add_flow(u, v, w);
    }
    printf("%lld", hlpp());
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值