增广路算法:
根据增广路地理,为了得到最大流,可以从任何一个可行流开始,沿着增广路对网络流进行增广,直到网络中不存在增广路为止,这样的算法称为增广路算法。
增广路算法流程如下。
(1)取一个可行流f作为初始流(如果没有给定可行流,则取零流作为初始流)。
(2)寻找关于f的增广路P,如果找到,则沿着这条增广路P将f改进成一个更大的流。
(3)重复 第(2)步直到找不到增广路为止。
增广路算法的关键是寻找增广路和改进网络流。
主要有三种增广路算法。(1)Ford_Fulkerson算法。(2)最短增广路算法。(3)Dinic算法(连续增广路算法)。后两种算法效率更高。
Ford_Fulkerson算法:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cctype>
#include <cmath>
#include <stack>
#include <queue>
#include <list>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000;
const int inf = 10000000;
struct arc
{
int c,f;//容量、流量
};
int n,m;
arc edge[maxn][maxn];
int flag[maxn]; //顶点状态 -1为标号 0已标号未检查 1已标号已检查
int prev[maxn]; //标号的第1个分量
int al[maxn]; //标号的第2个分量
void printFlow()
{
int maxFlow = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(i == 0 && edge[i][j].f != inf) maxFlow += edge[i][j].f;
if(edge[i][j].f != inf)
printf("%d->%d:%d\n",i,j,edge[i][j].f);
}
}
printf("maxFlow:%d\n",maxFlow);
}
void input()
{
int u,v,c,f;
scanf("%d%d",&n,&m);
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
edge[i][j].c = edge[i][j].f = inf;
}
for(int i = 0; i < m; i++)
{
scanf("%d%d%d%d",&u,&v,&c,&f);
edge[u][v].c = c;
edge[u][v].f = f;
}
}
void ford_fulkerson()
{
while(1)//直至标号不存在
{
queue<int> q;
memset(flag,-1,sizeof(flag));
memset(prev,0,sizeof(prev));
memset(al,0,sizeof(al));
flag[0] = 0; prev[0] = 0; al[0] = inf;
q.push(0);
//队列非空并且汇点未标号
while(!q.empty() && flag[n-1] == -1)
{
int v = q.front(); q.pop();
for(int i = 0; i < n; i++)
{
if(flag[i] == -1)//该顶点未标号
{
//正向且流量未满
if(edge[v][i].c != inf && edge[v][i].f < edge[v][i].c)
{
//标号
flag[i] = 0; prev[i] = v;
al[i] = min(al[v],edge[v][i].c - edge[v][i].f);
q.push(i);
}
//反向且有流量
else if(edge[i][v].c != inf && edge[i][v].f > 0)
{
flag[i] = 0; prev[i] = -v;
al[i] = min(al[v],edge[i][v].f);
q.push(i);
}
}
flag[v] = 1;//该顶点已检查
}
}//end of while
//汇点未标号或者调整量为0
if(flag[n-1] == -1 || al[n-1] == 0) break;
int p1 = n-1,p2 = abs(prev[p1]);
int a = al[n-1];
while(1)
{
if(edge[p2][p1].f != inf)
edge[p2][p1].f += a;
else
edge[p1][p2].f -= a;
if(p2 == 0) break;
p1 = p2;
p2 = abs(prev[p1]);
};
}//end of while(1)
//最大流
printFlow();
}//end of ford
int main()
{
input();
//初始流
printFlow();
ford_fulkerson();
return 0;
}
/*
input:
6 10
0 1 8 2
0 2 4 3
1 3 2 2
1 4 2 2
2 1 4 2
2 3 1 1
2 4 4 0
3 4 6 0
3 5 9 3
4 5 7 2
output:
0->1:2
0->2:3
1->3:2
1->4:2
2->1:2
2->3:1
2->4:0
3->4:0
3->5:3
4->5:2
maxFlow:5
0->1:4
0->2:4
1->3:2
1->4:2
2->1:0
2->3:1
2->4:3
3->4:0
3->5:3
4->5:5
maxFlow:8
*/
下面两个是两个改版Ford_Fulkerson算法,分别用dfs和bfs来寻找增广路:
bfs:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 1005;
const int inf = 100000;
struct Arc
{
int c,f;//容量、流量
};
int n,m;
Arc edge[maxn][maxn];
int vis[maxn];
int a[maxn];
int p[maxn];
void input()
{
int u,v,c,f;
scanf("%d%d",&n,&m);
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
edge[i][j].c = edge[i][j].f = inf;
}
}
for(int i = 0; i < m; i++){
scanf("%d%d%d%d",&u,&v,&c,&f);
edge[u][v].c = c;
edge[u][v].f = f;
}
}
//寻找增广路
int bfs()
{
queue<int> q;
memset(vis,0,sizeof(vis));
q.push(0);
vis[0] = 1;
a[0] = inf;
//找到一条增广路
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = 0; i < n; i++){
if(!vis[i]){
//正向且未满
if(edge[u][i].c != inf && edge[u][i].f < edge[u][i].c){
vis[i] = 1; p[i] = u;
a[i] = min(a[u],edge[u][i].c-edge[u][i].f);
q.push(i);
}
//反向且有流量
else if(edge[i][u].c != inf && edge[i][u].f > 0){
vis[i] = 1; p[i] = -u;
a[i] = min(a[u],edge[i][u].f);
q.push(i);
}
}
}
vis[u] = 1;
if(vis[n-1]) break;
}
if(!vis[n-1]) return 0;
//增广
int t = n-1;
int alpha = a[n-1];
while(t != 0){
if(p[t] >= 0){//正向
edge[p[t]][t].f += alpha;
}
else{//反向
edge[t][-p[t]].f -= alpha;
}
t = abs(p[t]);
}
return a[n-1];
}
void printFlow()
{
int maxFlow = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(i == 0 && edge[i][j].f != inf) maxFlow += edge[i][j].f;
if(edge[i][j].f != inf)
printf("%d->%d:%d\n",i,j,edge[i][j].f);
}
}
printf("maxFlow:%d\n",maxFlow);
}
int main()
{
input();
printFlow();
while(bfs());
printFlow();
return 0;
}
/*
input:
6 10
0 1 8 2
0 2 4 3
1 3 2 2
1 4 2 2
2 1 4 2
2 3 1 1
2 4 4 0
3 4 6 0
3 5 9 3
4 5 7 2
output:
0->1:2
0->2:3
1->3:2
1->4:2
2->1:2
2->3:1
2->4:0
3->4:0
3->5:3
4->5:2
maxFlow:5
0->1:4
0->2:4
1->3:2
1->4:2
2->1:0
2->3:1
2->4:3
3->4:0
3->5:3
4->5:5
maxFlow:8
*/
dfs:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 1005;
const int inf = 100000;
struct Arc
{
int c,f;//容量、流量
};
int n,m;
Arc edge[maxn][maxn];
int vis[maxn];
void input()
{
int u,v,c,f;
scanf("%d%d",&n,&m);
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
edge[i][j].c = edge[i][j].f = inf;
}
}
for(int i = 0; i < m; i++){
scanf("%d%d%d%d",&u,&v,&c,&f);
edge[u][v].c = c;
edge[u][v].f = f;
}
}
int dfs(int u, int alpha)
{
if(u == n-1) return alpha;
if(vis[u]) return 0;
vis[u] = 1;
for(int i = 0; i < n; i++){
if(!vis[i]){
int flow;
//正向且未满
if(edge[u][i].c != inf && edge[u][i].f < edge[u][i].c){
flow = dfs(i,min(alpha,edge[u][i].c-edge[u][i].f));
edge[u][i].f += flow;
if(flow != 0) return flow;
}
//反向且有流量
else if(edge[i][u].c != inf && edge[i][u].f > 0){
flow = dfs(i,min(alpha,edge[i][u].f));
edge[i][u].f -= flow;
if(flow != 0) return flow;
}
}
}
return 0;
}
void printFlow()
{
int maxFlow = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(i == 0 && edge[i][j].f != inf) maxFlow += edge[i][j].f;
if(edge[i][j].f != inf)
printf("%d->%d:%d\n",i,j,edge[i][j].f);
}
}
printf("maxFlow:%d\n",maxFlow);
}
int main()
{
input();
printFlow();
while(dfs(0,inf)){
//printFlow();
memset(vis,0,sizeof(vis));
}
printFlow();
return 0;
}
/*
input:
6 10
0 1 8 2
0 2 4 3
1 3 2 2
1 4 2 2
2 1 4 2
2 3 1 1
2 4 4 0
3 4 6 0
3 5 9 3
4 5 7 2
output:
0->1:2
0->2:3
1->3:2
1->4:2
2->1:2
2->3:1
2->4:0
3->4:0
3->5:3
4->5:2
maxFlow:5
0->1:4
0->2:4
1->3:2
1->4:2
2->1:0
2->3:1
2->4:3
3->4:0
3->5:3
4->5:5
maxFlow:8
*/