网络流模板及易错点总结

一、最大流

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 300,MM = 5e3 + 8,INF = 0x7f7f7f7f;
int n,m,s,t;
int dis[NN];
queue<int> q;
inline int read(){
	register int res = 0,flag = 1;
	register char c = getchar();
	while(!isdigit(c)){
		if(c == '-') flag = -1;
		c = getchar();
	}
	while(isdigit(c)){
		res = res * 10 + c - '0';
		c = getchar();
	}
	return res * flag;
}
struct Edge{
	int to,next,val;
}edge[MM << 1];
int head[NN],cnt,pre[NN];
void init(){
	cnt = 1;
	for(int i = 1; i <= n+1; i++)head[i] = pre[i] = -1;//head数组和pre数组都要赋初值为-1
} 
void add_edge(int u,int v,int w){
	edge[++cnt] = {v,head[u],w};
	head[u] = pre[u] = cnt;
} 
int bfs(){
	memset(dis,0,sizeof(dis));
	while(!q.empty())q.pop();//记得初始化清空队列
	q.push(s);dis[s] = 1;head[s] = pre[s];
	while(!q.empty()){
		int u = q.front();q.pop();
		for(int i = head[u]; i != -1; i = edge[i].next){
			int v = edge[i].to,w = edge[i].val;//edge[i].to不要写成next
			if(w && !dis[v]){
				q.push(v);
				head[v] = pre[v];//head初始化
				dis[v] = dis[u] + 1;
				if(v == t)return 1;
			}
		}
	}
	return 0;
}
ll dinic(int u,int flow){
	if(u == t)return flow;
	int rest = flow;
	//if(!rest) return 0;
	for(int &i = head[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].to,w = edge[i].val;
		if(w && dis[u] + 1 == dis[v]){
			int k = dinic(v,min(rest,w));//rest不要写成flow
			if(!k) dis[v] = 0;
			edge[i].val -= k;
			edge[i^1].val += k;//^1不能忘
			rest -= k; 
		}
		if(!rest)break;//当前弧优化的rest在后面判定
	}
	return flow - rest;
}
int main(){
	n = read(),m = read(),s = read(),t = read();
	init();
	for(int i = 1,u,v,w; i <= m; ++i){
		u = read(),v = read(),w = read();
		add_edge(u,v,w);add_edge(v,u,0);
	}
	ll ans = 0,flow = 0;
	while(bfs()){
		while(flow = dinic(s,INF)) ans += flow;//少掉while就会慢的一匹
	}
	printf("%lld",ans);
}

二、最小费用最大流

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

const int NN = 5e3 + 8,MM = 1e5 + 8,INF = 0x3f3f3f3f;
int n,m,s,t,cost;
bool vis[NN];

inline int read(){
	register int res = 0,flag = 1;
	register char c = getchar();
	while(!isdigit(c)){
		if(c == '0')flag = -1;c = getchar();
	}
	while(isdigit(c)){
		res = res * 10 + c - '0';
		c = getchar();
	}
	return res * flag;
}

struct Edge{
	int to,next,val,water;
}edge[MM << 1];
int head[NN],pre[NN],cnt;
void init(){
	cnt = 1;
	for(int i = 1; i <= n; ++i)head[i] = pre[i] = -1;//两个数组都要初始化
}
void add_edge(int u,int v,int w,int flow){
	edge[++cnt] = {v,head[u],w,flow};
	head[u] = pre[u] = cnt;//两个数组都要更新
}

queue<int> q;
int dis[NN];
bool SPFA(){
	memset(dis,0x3f,sizeof(dis));
	vis[s] = 1;
	while(!q.empty())q.pop();
	q.push(s);head[s] = pre[s];dis[s] = 0;//初始化一个都不能忘,特别是vis
	while(!q.empty()){
		int u = q.front();q.pop();
		vis[u] = 0;
		for(int i = head[u]; i != -1; i = edge[i].next){
			int v = edge[i].to,water = edge[i].water,val = edge[i].val;
			if(water && dis[v] > dis[u] + val){
				dis[v] = dis[u] + val;
				head[v] = pre[v];
				if(!vis[v])q.push(v),vis[v] = 1;
			}
		}
	}
	return dis[t] != INF;//这该是只能放后面的吧
}

int dfs(int u,int flow){
	if(u == t)return flow;
	int rest = flow;
	vis[u] = 1;
	if(!rest) return 0;
	for(int &i = head[u]; i != -1; i = edge[i].next){
		int v = edge[i].to,water = edge[i].water,val = edge[i].val;
		if(!vis[v] && dis[u] + val == dis[v] && water){
			int x = dfs(v,min(water,rest));//rest不能写成flow
			if(!x) dis[v] = 0;
			cost += x * val;
			rest -= x;
			edge[i].water -= x;edge[i^1].water += x;
		}
		if(!rest)break;
	} 
	vis[u] = 0;
	return flow - rest;
}
int main(){
	n = read(); m = read(); s = read(); t = read();
	init();
	for(int i = 1,u,v,w,f; i <= m; ++i){
		u = read();v = read();f = read();w = read();
		add_edge(u,v,w,f);
		add_edge(v,u,-w,0);//反边的代价为负,容量为0
	}
	int ans = 0,flow = 0;
	while(SPFA()){
		while(flow = dfs(s,INF)) ans += flow;
	}
	printf("%d %d",ans,cost);
}

三、有源汇有上下界最大流

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f, NN = 1e6 + 8, MM = 1e6 + 8;
int n,m,s1,s2,t1,t2,S,T;
int ds[NN];
struct Edge{
	int to,next,val;
}edge[MM << 1];
int head[NN],cnt,pre[NN];
void init(){
	cnt = 1;
	memset(ds,0,sizeof(ds));
	for(int i = 0; i < NN; ++i)head[i] = pre[i] = -1;
}
void add_edge(int u,int v,int w){
	edge[++cnt] = {v,head[u],w};
	head[u] = pre[u] = cnt;
}

queue<int> q;

int sum,e;
int dis[NN];
bool bfs() {
	while(!q.empty())q.pop();
	memset(dis,0,sizeof(dis));
	q.push(S);head[S] = pre[S];dis[S] = 1;
	while(!q.empty()){
		int u = q.front();q.pop();
		for(int i = head[u]; i != -1; i = edge[i].next){
			int v = edge[i].to,val = edge[i].val;
			if(!dis[v] && val){
				dis[v] = dis[u] + 1;
				head[v] = pre[v];
				if(v == T) return 1;
				q.push(v);
			}
		}
	}
	return 0;
}
int dfs(int u,int flow){
	if(u == T) return flow;
	int rest = flow;
	for(int &i = head[u]; i != -1; i = edge[i].next) {
		int v = edge[i].to,val = edge[i].val;
		if(val && dis[u] + 1 == dis[v]){
			int k = dfs(v,min(rest,val));
			if(!k) dis[v] = 0;
			edge[i].val -= k;edge[i^1].val += k;
			rest -= k;
		}
		if(!rest)break;
	}
	return flow - rest;
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		init();
		s1 = n + m + 1;t1 = n + m + 2;s2 = n + m + 3;t2 = n + m + 4;
		for(int i = n + 1,v; i <= m + n; ++i){
			scanf("%d",&v);
			ds[t1] += v; ds[i] -= v;
			add_edge(i,t1,INF-v);//少女向汇点连边 
			add_edge(t1,i,0);
		}
		for(int i = 1,c,w; i <= n; ++i){
			scanf("%d%d",&c,&w);
			add_edge(s1,i,w);
			add_edge(i,s1,0);
			for(int j = 1,x,l,r; j <= c; ++j){
				scanf("%d%d%d",&x,&l,&r);
				++x;
				add_edge(i,x + n,r - l);//天数向少女连边 
				add_edge(x + n,i,0);
				ds[i] -= l;
				ds[x + n] += l;
			}
		}
		int ans = 0;
		for(int i = 1; i <= n + m + 2; i++) {
            if(ds[i] > 0) {
                ans += ds[i];
                add_edge(s2, i, ds[i]);
                add_edge(i, s2, 0);
            }
            else if(ds[i] < 0){
            	add_edge(i, t2, -ds[i]);
                add_edge(t2, i, 0);
			}
        }
        add_edge(t1,s1,INF);
        add_edge(s1,t1,0);
        int ans1 = 0,ans2 = 0,flow;
        S = s2;T = t2;
        while(bfs()){
        	while(flow = dfs(S,INF)){
        		ans1 += flow;
			}
		}
        if(ans1 != ans)printf("-1\n\n");
        else{
        	int res=edge[cnt-2].val;
			edge[cnt-1].val=0, edge[cnt-2].val=0;
			S=s1, T=t1;
			while(bfs())
				while(flow = dfs(S,INF)) ans2 += flow;
			printf("%d\n\n",ans2);
		}
	}
	
}

原文链接: https://www.cnblogs.com/rickylin/p/17049582.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    网络流模板及易错点总结

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/312030

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 下午12:14
下一篇 2023年2月16日 下午12:15

相关推荐