基于最大流的最小花费

洛谷

#include<bits/stdc++.h>
using namespace std;
const int N = 50005, M = 50000 * 2 + 5;

int h[N], e[M], ne[M], flow[M], cost[M], idx;
int n, m, S, T;
int dist[N], pre[N];
bool st[N];

void add(int a, int b, int v, int c) {
	flow[idx] = v, cost[idx] = c, e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

bool spfa() {                     //找最短路,因为有负权边,所以用改良的Ford,即是spfa()
	for (int i = 1; i <= n; i++) dist[i] = 2e9, st[i] = false, pre[i] = -1;
	dist[S] = 0;
	queue<int> q;
	q.push(S);
	st[S] = true;
	while (q.size()) {
		int x = q.front();
		q.pop();
		st[x] = false;
		for (int i = h[x]; ~i; i = ne[i]) {
			int j = e[i];
			if (flow[i] && dist[j] > dist[x] + cost[i]) {
				dist[j] = dist[x] + cost[i];
				pre[j] = i;   //记录一下该点是由那条边扩展而来的
				if (!st[j]) st[j] = true, q.push(j);
			}
		}
	}
	if (pre[T] == -1) return false;   //看T是否在余图中
	return true;
}

int maxflow(int &c) {                //返回最大流量,c是对应的最小花费
	int res = 0;
	while (spfa()) {
		int minv = INT_MAX, cur = pre[T];
		while (cur != -1)
			minv = min(minv, flow[cur]), cur = pre[e[cur ^ 1]];  //从末点向前推,得到所能增加的最大流量
		cur = pre[T];
		while (cur != -1)
			flow[cur] -= minv, flow[cur ^ 1] += minv, c += cost[cur] * minv, cur = pre[e[cur ^ 1]]; //对应的修改余图
		res += minv;
	}
	return res;
}

int main() {
	memset(h, -1, sizeof h);
	cin >> n >> m >> S >> T;
	while (m--) {
		int x, y, z, c;
		scanf("%d%d%d%d", &x, &y, &z, &c);
		add(x, y, z, c), add(y, x, 0, -c);
	}
	int c = 0;
	int ans = maxflow(c);
	cout << ans << ' ' << c << endl;
	return 0;
}
posted @   兮何其  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示