二分图最大匹配

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

左端点到右端点连容量为 \(1\) 的边,超级源点到每个左端点连容量为 \(1\) 的边,每个右端点到超级汇点连容量为 \(1\) 的边,求最大流即可。

代码

//author:kzssCCC

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

const ll INF = 9e18;

void solve(){
	int L,R,m;
	cin >> L >> R >> m;

	int n = L+R;
	vector<vector<array<ll,3>>> adj(n+3);

	auto add = [&](int u,int v,ll w){
		adj[u].push_back({w,(int)adj[v].size(),v});
		adj[v].push_back({0,(int)adj[u].size()-1,u});
	};

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

		add(u,v+L,1);
	}

	int s = n+1;
	int t = n+2;
	for (int i=1;i<=L;i++){
		add(s,i,1);
	}
	for (int i=L+1;i<=n;i++){
		add(i,t,1);
	}

	int N = n+2;
	vector<int> cur,depth;
	auto bfs = [&](){
		depth = vector<int>(N+1,-1);
		queue<int> q;
		depth[s] = 0;
		q.push(s);

		while (!q.empty()){
			int u = q.front();
			q.pop();

			for (auto& [w,rev,v]:adj[u]){
				if (w>0 && depth[v]==-1){
					depth[v] = depth[u]+1;
					q.push(v);
				}
			}
		}

		return depth[t]!=-1;
	};

	ll mxf = 0;

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

		for (int& i=cur[u];i<len;i++){
			auto& [w,rev,v] = adj[u][i];
			if (w>0 && depth[v]==depth[u]+1){
				ll f = dfs(v,min(mf,w));
				w -= f;
				adj[v][rev][0] += f;

				sum += f;
				mf -= f;
				if (mf==0) break;
			}
		}

		return sum;
	};

	while (bfs()){
		cur = vector<int>(N+1);
		mxf += dfs(s,INF);
	}

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

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

	return 0;
}
posted @ 2026-05-19 14:34  kzssCCC  阅读(7)  评论(0)    收藏  举报