0
点赞
收藏
分享

微信扫一扫

网络流专题班例题和练习

三次方 2022-01-21 阅读 61

文章目录

概念

网络流图

若有向图 G = ( V , E ) G=(V,E) G=(V,E)满足:

  • 有且仅有一个顶点 S S S,它的入读为 0 0 0,即 d − ( S ) = 0 d-(S) = 0 d(S)=0,这个顶点S便称为源点。
  • 有且仅有一个顶点 T T T,它的出度为 0 0 0,即 d + ( T ) = 0 d+(T) = 0 d+(T)=0,这个顶点T便称为汇点。
  • 每一条弧都有非负数,叫做这个边的容量。边 ( v i , v j ) (vi,vj) (vi,vj)的容量用 C i j Cij Cij表示
    则称之为网络流图,记为 G = ( V , E , C ) G = (V,E,C) =(V,E,C)

可行流

f f fi,j表示从 i i i j j j的流量,满足:

  • 没一条弧 ( i , j ) (i,j) (i,j) f f fi,j < = C <= C <=Ci,j
  • 流量平衡:除源点和汇点以外的所有点 v i vi vi,有 Σ Σ Σj f f fi,j = Σ = Σ =Σk f f fj,k
  • 对于源点 S S S和汇点 T T T有, Σ i f Σif ΣifS,i = Σ j f = Σjf =Σjfj,T = v ( f ) = v(f) =v(f)

可改进路(增广路)

找到一条路径,使原来 S − > T S->T S>T的流量增加。

残留网络

由残留的容量(边的容量减去可行流)以及源点汇点构成的网络。

在容量网络 G ( V , E ) G(V, E) G(V,E) 中, 设 E ′ ⊆ E E'⊆E EE, 如果在 G G G 的基图中删去 E ′ E' E 后不再连通, 则称 E ′ E' E G G G 的割。割将 G G G 的顶点集 V V V 划分成两个子集 S S S T = V − S T = V - S T=VS。将割记为 ( S , T ) (S, T) (S,T)

基本理论

  • 对于 S − T S-T ST一个可行流 f , f f,f f,f一定小于割的容量。
  • 可行流f是最大流的充分必要条件是:残留网络中不存在可改进流量。
  • 最大流最小割定理 - 最大流等于最小割

求最大流思路

FF方法

  1. 初始化网络中各个边的容量, c < u , v > c<u,v> c<u,v>为该边的容量, c < u , v > c<u,v> c<u,v>为初始化0。
  2. 在残留网络中找到一条 s s s t t t的增广路。能找到到3,不能到5
  3. 在增广路中找到容量最小的边记为 x x x,加到最大流中。
  4. 在增广路中所有边的流量减去 x x x,反向边加上 x x x,构成新的残留网络,转到2
  5. 得到最大流。

EK算法

int EK(int s,int t){
    int flow = 0 ;
    while(1){
        memset(a,0,sizeof a);
        queue<int> q;
        q.push(s);
        a[s] = inf;
        while(!q.empty()){
            int u = q.front();q.pop();
            for(int i = h[u];~i;i=ne[i]){
                int y = e[i];
                if(!a[y] && w[i] > 0){
                    a[y] = min(a[u],w[i]);
                    pre[y] = i;
                    q.push(y);
                }
            }
            if(a[t])break;
        }
        if(!a[t])break;
        for(int i = t;i!=s;i=e[pre[i]^1]){
			w[pre[i]] -= a[t],w[pre[i]^1] += a[t];
		}
        flow += a[t];
    }
    return flow;
}

dinic

bool dfs(int s,int t){
	memset(st,0,sizeof st);
	memset(d,inf,sizeof d);
	queue<int> q;
	q.push(s);
	st[s] = true;
	d[s] = 0;
	while(!q.empty()){
		int u = q.front();q.pop();
		st[u] = false;
		for(int i = h[u];~i;i=ne[i]){
			int y = e[i];
			if(w[i] > 0 && d[y] > d[u] + 1){
				d[y] = d[u] + 1;
				if(!st[y])q.push(y); 
			}
		}
	}
	return d[t] != inf;
}
int bfs(int s,int mw,int t){
	if(s == t)return mw;
	for(int &i = cur[s];~i;i=ne[i]){
		int y = e[i];
		if(w[i] <= 0 || d[y] != d[s] + 1)continue;
		int cw = bfs(y,min(mw,w[i]),t);
		if(cw <= 0)continue;
		w[i] -= cw;
		w[i^1] += cw;
		return cw; 
	}
	return 0;
}
int dinic(int s,int t){
	int flow = 0;
	while(dfs(s,t)){
		memcpy(cur,h,sizeof h);
		while(int d = bfs(s,inf,t)) flow += d;
	}
	return flow;
}

最小费用最大流

保证S-T流量最大的情况下,所需费用最小。

EK+spfa

bool spfa(int s,int t){
	for(int i = 1;i<N;i++)dist[i] = inf,d[i] = 0,st[i] = 0;
	dist[s] = 0,d[s] = inf,st[s] = true;
	queue<int> q;
	q.push(s);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		st[u] = false;
		for(int i = h[u];~i;i=ne[i]){
			int y = e[i];
			if(f[i] && dist[y] > dist[u] + w[i]){
				dist[y] = dist[u] + w[i];
				d[y] = min(d[u],f[i]);
				pre[y] = i;	
				if(!st[y]){
					q.push(y);
					st[y] = true; 
				}
			}
		}		
	}
	return  dist[t] != inf;
}
int EK(int s,int t){
	int cost = 0,flow = 0;
	while(spfa(s,t)){
		for(int i = t;i!=s;i=e[pre[i]^1]){
			f[pre[i]] -= d[t];
			f[pre[i]^1] += d[t];
		}
		//根据条件改变
		cost += dist[t]*d[t];	
	    flow += d[t];
	}
	return cost,flow;	
}

例 题

poj Power Network

题目链接

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
//526526
using namespace std;
const int N=310,M = 3e4+10,inf = 0x3f3f3f3f;
int h[N],ne[M],e[M],f[M],idx;
int d[N];
void add(int a,int b,int c){
	ne[idx] = h[a],e[idx] = b,f[idx] = c,h[a] = idx++;
	ne[idx] = h[b],e[idx] = a,f[idx] = 0,h[b] = idx++;
}
int cur[N];
bool st[N];
int n,n1,n2,m;
int a[N],pre[N];
int S = 101,T=102;
/*
int EK(){
	int flow = 0;
	while(1){
		memset(a,0,sizeof a);
		queue<int> q;
		q.push(S);
		a[S] = inf;
		while(!q.empty()){
			int u = q.front();q.pop();
			for(int i = h[u];~i;i=ne[i]){
				int y = e[i];
				if(!a[y] && f[i] > 0){
					a[y] = min(a[u],f[i]);
					pre[y] = i;
					q.push(y);
				}
			}
			if(a[T])break;
		}
		if(!a[T])break;
		for(int i = T;i!=S;i=e[pre[i]^1]){
			f[pre[i]] -= a[T];
			f[pre[i]^1] += a[T];
		}
		flow += a[T];
	}
	return flow;
}
*/
bool dfs(int s,int t){
	memset(st,0,sizeof st);
	memset(d,inf,sizeof d);
	queue<int> q;
	q.push(s);
	st[s] = true;
	d[s] = 0;
	while(!q.empty()){
		int u = q.front();q.pop();
		st[u] = false;
		for(int i = h[u];~i;i=ne[i]){
			int y = e[i];
			if(f[i] > 0 && d[y] > d[u] + 1){
				d[y] = d[u] + 1;
				if(!st[y])q.push(y); 
			}
		}
	}
	return d[t] != inf;
}
int bfs(int s,int mw,int t){
	if(s == t)return mw;
	for(int &i = cur[s];~i;i=ne[i]){
		int y = e[i];
		if(f[i] <= 0 || d[y] != d[s] + 1)continue;
		int cw = bfs(y,min(mw,f[i]),t);
		if(cw <= 0)continue;
		f[i] -= cw;
		f[i^1] += cw;
		return cw; 
	}
	return 0;
}
int dinic(int s,int t){
	int flow = 0;
	while(dfs(s,t)){
		memcpy(cur,h,sizeof h);
		while(int d = bfs(s,inf,t)) flow += d;
	}
	return flow;
}
int main(){

	while(cin >> n >> n1 >> n2 >> m){
		idx = 0;
		memset(h,-1,sizeof h);	
		int a,b,c;
		char t ; 
		for(int i = 1;i<=m;i++){
			cin >> t >> a >> t >> b >> t >> c; 
			add(a,b,c);
		}
		for(int i = 1;i<=n1;i++){
			cin >> t >> a >> t >> b;
			add(S,a,b);
		}
		for(int i = 1;i<=n2;i++){
			cin >> t >> a >> t >> b;
			add(a,T,b);
		}
		cout << dinic(S,T) << endl;	
	}
	return 0;
} 

举报

相关推荐

0 条评论