网络流算法 网络流算法用于解决从源点到汇点最大流的问题。 Edmonds-Karp算法 算法主要思想: 每次BFS找到一条从源点到汇点的最少路径数的可行路径,同时把这条路径塞满,这条路上的最小容量即为这条路径的流量。然后将这条路径的正向边删除,增加一条容量相同的反向边,当BFS无法进行下去的时候,则算法结束,最大流为每次BFS找到的可行路径的流量和。
Poj1273 Drainage Ditches
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <queue> #include <iostream> using namespace std; int G[300][300]; bool visited[300]; int Prev[300]; int n,m; int Augment() { int v; bool bFindPath; memset(Prev,0,sizeof(Prev)); memset(visited,0,sizeof(visited)); deque<int> q; Prev[1]=0; visited[1]=1; q.push_back(1); bFindPath=false; //bfs找到从源到汇的一条路径 while(!q.empty()) { v=q.front(); q.pop_front(); for(int i=1;i<=m;i++) { if(G[v][i]>0 && visited[i]==0) { Prev[i]=v; visited[i]=1; if(i==m) { bFindPath=true; q.clear(); break; } else { q.push_back(i); } } } } int nMinFlow=9999999; if(!bFindPath) return 0; //构建新残余网络,构建增广路径 v=m; while(Prev[v]) { nMinFlow=min(nMinFlow,G[Prev[v]][v]); v=Prev[v]; } v=m; while(Prev[v]) { G[Prev[v]][v]-=nMinFlow; G[v][Prev[v]]+=nMinFlow; v=Prev[v]; } return nMinFlow; } int main() { int s,e,c; while(scanf("%d %d",&n,&m)!=EOF) { memset(G,0,sizeof(G)); for(int i=1;i<=n;i++) { scanf("%d %d %d",&s,&e,&c); G[s][e]+=c; } int nMaxFlow=0; int aug; while(aug=Augment()) //每次通过bfs找到一个可行路径 { nMaxFlow+=aug; } printf("%d\n",nMaxFlow); } return 0; }
2.Dinic算法
为了少做几次bfs。
解决方法:先对结点进行分层,然后以层次数进行dfs,这样一次的增广过程可以通过dfs找到几条可行路径。结点回溯回溯到该路径的流量对应的最小层数容量边的起点。同时还要注意要将原图备份,使用原图上的边的容量减去做完最大流的残余网络上的边的剩余容量,就是边的容量。
POJ 3436 ACM Computer Factory
#include <iostream> #include <queue> #include <algorithm> #include <cstdio> #include <string.h> #include <stdlib.h> using namespace std; #define MYMAX 120 #define INFINITE 99999999 int P, N; int T; //汇总编号 struct Machine { int Q; int in[12]; int out[12]; } Machines[100]; int G[MYMAX][MYMAX]; // Machines[i] 对应于节点 i 和 i + N,两者之间连边权为Machines[i].Q int G2[MYMAX][MYMAX]; // Machines[i] 对应于节点 i 和 i + N,两者之间连边权为Machines[i].Q int MaxFlow; bool MyEqual( int * s1, int * s2,int P) { for( int i = 0;i < P;i ++ ) { if( s1[i] != s2[i] && s1[i] != 2 && s2[i] != 2 ) return false; } return true; } int Visited[MYMAX]; int Layer[MYMAX]; bool CountLayer() { deque<int> q; memset(Layer,0xff,sizeof(Layer)); q.push_back(0); Layer[0] = 0; while(!q.empty()) { int v = q.front(); q.pop_front(); for( int i = 0;i <= T; i ++ ) { if( G[v][i] > 0 && Layer[i] == -1 ) { Layer[i] = Layer[v] + 1; if( i == T ) return true; else q.push_back(i); } } } return false; } int Dinic() { deque<int> q; int i; int nMaxFlow = 0; while( CountLayer()) { memset(Visited,0,sizeof(Visited)); q.push_back(0); Visited[0] = 1; while( ! q.empty()) { int v = q.back(); if( v == T ) { int nMinC = INFINITE,nMinC_vs; for( i = 1;i < q.size();i ++ ) { int vs = q[i-1]; int ve = q[i]; if( G[vs][ve] > 0 && nMinC > G[vs][ve]) { nMinC = G[vs][ve]; nMinC_vs = vs; } } nMaxFlow += nMinC; for( i = 1;i < q.size();i ++ ) { int vs = q[i-1]; int ve = q[i]; G[vs][ve] -= nMinC; G[ve][vs] += nMinC; } while( ! q.empty() && q.back() != nMinC_vs) { Visited[q.back()] = 0; q.pop_back(); } } else { for( i = 0;i <= T;i ++ ) { if( G[v][i] > 0 && Layer[i] == Layer[v] + 1 && ! Visited[i] ) { Visited[i] = 1; q.push_back(i); break; } } if( i > T ) q.pop_back(); } } } return nMaxFlow; } int main() { cin >> P >> N;//P个组件,N个机器 int i,j; memset(G,0,sizeof(G)); for( i = 1;i <= N; i ++) { scanf("%d",&Machines[i].Q); for( j = 0; j < P; j ++ ) scanf("%d", & Machines[i].in[j]); for( j = 0; j < P; j ++ ) scanf("%d", & Machines[i].out[j]); G[i][i+N] = Machines[i].Q; } T = 2 * N + 1; //汇点编号 //每个机器拆成两个点 i 和 i + N,一个用于接收部件,一个用于产出 //从i 到i + N 连边,容量 就是 Qi for( i = 1; i <= N ; i ++ ) { for( j = i + 1 ; j <= N; j ++ ) { if( MyEqual( Machines[i].out, Machines[j].in,P )) G[i+N][j] = INFINITE; if( MyEqual( Machines[j].out, Machines[i].in,P )) G[j+N][i] = INFINITE; } int k; G[0][i] = INFINITE; for( k = 0; k < P; k ++ ) if( Machines[i].in[k] == 1 ) { G[0][i] = 0; break; } G[i+N][T] = INFINITE; for( k = 0; k < P; k ++ ) if( Machines[i].out[k] == 0 || Machines[i].out[k] == 2 ) { G[i+N][T] = 0; break; } } memcpy(G2, G,sizeof(G)); int nMaxFlow = Dinic(); int nEdges = 0; for( i = N + 1; i < T;i ++ ) for( j = 1; j <= N; j ++ ) if( G[i][j] < G2[i][j] ) nEdges ++; cout << nMaxFlow << " " << nEdges << endl; for( i = N + 1; i < T;i ++ ) for( j = 1; j <= N; j ++ ) if( G[i][j] < G2[i][j] ) cout << i - N << " " << j << " " << G2[i][j] - G[i][j] << endl; return 0; }
其他典型例题:
poj2112 Optimal Milking
Poj1149 pigs
3. 有流量下界的网络最大流处理方法:
思路:分离下界
添加新的节点X,Y,使得X,Y成为新图的源点和汇点,若新图的最大流中,源点Y的所有发出边全部被覆盖,则原图有解,否则无解。这样就转换成了普通网络流问题进行解决。
POj2396 Budget
4.最小费用最大流
每条边上多了一个输送单位流量的费用参数,在最大流中寻找一个费用最小的最大流.
POJ 2135
#include <stdio.h> #include <queue> #include <iostream> #include <stdlib.h> #include <algorithm> #include <string.h> using namespace std; #define MAXN 1000 #define MAXM 20000 struct Edge { int a,b,cost,flow; }edge[MAXM+1]; int father[MAXN+1]; int reach[MAXN+1]; int cost[MAXN+1]; int m,n; int FindPath(int s,int t) { int ans,a,b,c,temp; int i; memset(reach, 0, sizeof(reach)); reach[s]=1; cost[s]=0; int fix; fix=0; while(!fix) { fix=1; for(i=1;i<=m;i++) { a=edge[i].a; b=edge[i].b; c=edge[i].cost; if(edge[i].flow>0) { if(reach[b]) { temp=cost[b]-c; if(!reach[a] || cost[a]>temp) { cost[a]=temp; reach[a]=1; father[a]=-i; fix=0; } } } else { if(reach[a]) { temp=cost[a]+c; if(!reach[b] || cost[b]>temp) { cost[b]=temp; reach[b]=1; father[b]=i; fix=0; } } } } } if(!reach[t]) return -1; else { b=t; while(b!=s) { i=father[b]; if(i>0) { edge[i].flow++; b=edge[i].a; } else { edge[-i].flow--; b=edge[-i].b; } } } return cost[t]; } void Solve() { int ans; for(int i=1;i<=m;i++) { edge[i+m].a=edge[i].b; edge[i+m].b=edge[i].a; edge[i+m].cost=edge[i].cost; } m=m+m; ans=FindPath(1,n)+FindPath(1,n); printf("%d\n",ans); } int main() { scanf("%d %d",&n,&m);//n个点,m条边 for(int i=1;i<=m;i++) scanf("%d %d %d",&edge[i].a,&edge[i].b,&edge[i].cost); Solve(); return 0; }
相关推荐
北京大学网络流算法 内部资料 经典算法
网络流算法的详细介绍,包括Ford-Fulkerson 算法、Edmonds-Karp 算法、Dinic 算法。有详细图例,很容易理解
非常详细的有关网络流算法的介绍与分析,杭州学军中学魏越闽
网络流算法和PASCAL程序
这个是网络流算法艺术,大家快来看看吧!强烈推荐!
算法设计与分析:06 网络流算法.pdf
网络流算法PPT学习教案.pptx
网络流算法 最大流 最小费用最大流算法的详细执行过程
而网络流算法正是图论算法中的一个重要分支,它特点突出、作用显著,因此应用范围十分广范,在近年来的各级别信息学竞赛中更是层出不穷,并且它还将占据着越来越重要的地位。 本文旨在通过剖析若干应用实例,逐步...
ACM网络流算法讲义ACM网络流算法讲义ACM网络流算法讲义
图论算法 ---最大流问题 网络流算法
网络流算法模版--C++写的 Edmonds-Karp算法
本文是dinic网络流算法的源程序,是一套模板,经过本人测试,适合参加ACM的同志!
网络流算法(没有价值) 。
北京大学2011年暑期acm培训课件 课程内容共八个专题,除理论知识外还包括精选例题讲解(先后次序可能调整...7) 网络流算法:基本的网络流算法,Dinic算法,带上下界的网络流,最小费用流 8) 数学题:组合数学,数论等
ACM,网络流算法,最小匹配问题等,ppt,代码。