网络流之最大流

网络流之最大流

例题

网络流一般可以解决形如以上的类似匹配的问题,将复杂,抽象的问题转化成图,在图上跑bfs,dfs,从而简化问题难度。

如此题,有N个插头,M个插座,部分插头可以转化为其他插头,插座与一个插头适配,问最小没有被插的插座的数量,我们可以设一个源点连向插头,插头连向插座,再将插座连想汇点跑最大流即可出答案。

#include<iostream>
#include<cstdio>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const ll inf=1e18,N =300007, M = 300007;
struct node {
	ll to, next;
	ll w;
}edge[M];
ll tot, head[N];
void addedge(ll u, ll v, ll w) {
	edge[++tot].to = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot;
	edge[++tot].to = u; edge[tot].w = 0; edge[tot].next = head[v]; head[v] = tot;
}
ll maxflow;
ll n,m,s,t,k,cnt;
ll deep[N]; //层级数,其实应该是level
ll now[M]; //当前弧优化
queue <ll> q;
bool bfs() {
	for(int i = 1;i <= t; i++) deep[i] = inf;
	while(!q.empty()) q.pop();
	q.push(s); deep[s] = 0; now[s] = head[s];
	while(!q.empty()) {
		ll u = q.front(); q.pop();
		for(int i = head[u]; i; i = edge[i].next) {
			ll v = edge[i].to;
			if(edge[i].w && deep[v] == inf) {
				q.push(v);
				now[v] = head[v];
				deep[v] = deep[u] + 1;
				if(v == t) return 1;
			}
		}
	}
	return 0;
}
//flow是整条增广路对最大流的贡献,rest是当前最小剩余容量,用rest去更新flow
ll dfs(ll u, ll flow) {
	if(u == t) return flow;
	ll ans = 0;
	for(int i = now[u];i && flow; i = edge[i].next) {
		now[u] = i; //当前弧优化(避免重复遍历从x出发的不可拓展的边)
		ll v = edge[i].to;
		if(edge[i].w && deep[v] == deep[u]+1) { //必须是下一层并且剩余容量大于0
			ll k = dfs(v, min(flow, edge[i].w)); //取最小
			if(!k) deep[v] = inf; //剪枝,去掉增广完毕的点
			edge[i].w -= k; //回溯时更新
			edge[i^1].w += k; //成对变换
			ans += k;
			flow -= k;
		}
	}
	return ans;
}
void dinic() {
	while(bfs())
		maxflow += dfs(s, inf);
}
string s1,s2;
map<string,ll>ma;
int main(){
	scanf("%lld",&n);
	tot=1;
	s=1000,t=1001;
	for(int i=1;i<=n;i++){
		cin>>s1;
		if(ma[s1]==0){
			ma[s1]=++cnt;
			addedge(ma[s1],t,1);
		}
	}
	scanf("%lld",&m);
	for(int i=1;i<=m;i++){
		cin>>s1>>s2;
		addedge(s,++cnt,1);
		if(ma[s2]==0){
			ma[s2]=++cnt;
			addedge(cnt-1,ma[s2],1);
		}
		else{
			addedge(cnt,ma[s2],1);
		}
	}
	scanf("%lld",&k);
	for(int i=1;i<=k;i++){
		cin>>s1>>s2;
		if(ma[s1]==0){
			ma[s1]=++cnt;
		}
		if(ma[s2]==0){
			ma[s2]=++cnt;
		}
		addedge(ma[s1],ma[s2],inf);
	}
	dinic();
	printf("%lld
",m-maxflow);
}
原文地址:https://www.cnblogs.com/whitelily/p/14034699.html