最小费用最大流(Primal-Dual 原始对偶算法+多路增广)

https://www.luogu.com.cn/problem/P3381

先做一次 \(spfa\) 求势能,然后重复 \(dijkstra\)\(dfs\) 在残留网络中累加流量和费用。

\(dfs\) 需要用 \(vis\) 标记访问节点,防止受 \(0\) 费用边影响无限循环。

每轮 \(dfs\) 结束后,更新势能数组,具体就是 \(h_i\) 直接加上 \(dis_i\)

代码

//author:kzssCCC

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

const ll INF = 9e18;

void solve(){
	int n,m,s,t;
	cin >> n >> m >> s >> t;

	vector<vector<array<int,4>>> adj(n+1);
	auto add = [&](int u,int v,int w,int c){
		adj[u].push_back({w,c,(int)adj[v].size(),v});
		adj[v].push_back({0,-c,(int)adj[u].size()-1,u});
	};

	for (int i=0;i<m;i++){
		int u,v,w,c;
		cin >> u >> v >> w >> c;
		add(u,v,w,c);
	}

	vector<ll> h(n+1);
	vector<bool> vis(n+1,true);
	queue<int> q;

	for (int i=1;i<=n;i++){
		q.push(i);
	}

	while (!q.empty()){
		int u = q.front();
		q.pop();
		vis[u] = false;

		for (auto& [w,c,rev,v]:adj[u]){
			if (w>0 && h[u]+c<h[v]){
				h[v] = h[u]+c;
				if (!vis[v]){
					q.push(v);
					vis[v] = true;
				}
			}
		}
	}

	vector<int> cur;
	vector<ll> dis;

	auto dij = [&](){
		dis = vector<ll>(n+1,INF);
		priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<>> pq;
		dis[s] = 0;
		pq.emplace(0,s);

		while (!pq.empty()){
			auto [d,u] = pq.top();
			pq.pop();

			if (d>dis[u]) continue;
			for (auto& [w,c,rev,v]:adj[u]){
				if (w>0 && d+h[u]-h[v]+c<dis[v]){
					dis[v] = d+h[u]-h[v]+c;
					pq.emplace(dis[v],v);
				}
			}
		}

		return dis[t]!=INF;
	};

	ll mxf = 0;
	ll cost = 0;

	function<ll(int,ll)> dfs = [&](int u,ll mf){
		if (u==t) return mf;
		ll sum = 0;
		int len = adj[u].size();
		vis[u] = true;

		for (int& i=cur[u];i<len;i++){
			auto& [w,c,rev,v] = adj[u][i];

			if (w>0 && !vis[v] && dis[u]+h[u]-h[v]+c==dis[v]){
				ll f = dfs(v,min(mf,(ll)w));
				mf -= f;
				w -= f;
				sum += f;
				adj[v][rev][0] += f;

				if (mf==0) break;
			}
		}

		return sum;
	};

	while (dij()){
		cur = vector<int>(n+1);
		vis = vector<bool>(n+1,false);
		
		ll f = dfs(s,INF);
		mxf += f;
		cost += (dis[t]-h[s]+h[t])*f;

		for (int i=1;i<=n;i++){
			if (dis[i]!=INF){
				h[i] += dis[i];
			}
		}
	}

	cout << mxf << ' ' << cost << '\n';
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t = 1;
	// cin >> t;
	while (t--) solve();

	return 0;
}
posted @ 2026-04-14 00:49  kzssCCC  阅读(12)  评论(0)    收藏  举报