网络最大流求解 增广路算法

来源:互联网 发布:nginx php 跨域 编辑:程序博客网 时间:2024/04/27 22:25

增广路算法:

根据增广路地理,为了得到最大流,可以从任何一个可行流开始,沿着增广路对网络流进行增广,直到网络中不存在增广路为止,这样的算法称为增广路算法。

增广路算法流程如下。

(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 fordint main(){input();//初始流 printFlow();ford_fulkerson(); return 0;}/* input: 6 100 1 8 20 2 4 31 3 2 21 4 2 22 1 4 22 3 1 12 4 4 03 4 6 03 5 9 34 5 7 2output:0->1:20->2:31->3:21->4:22->1:22->3:12->4:03->4:03->5:34->5:2maxFlow:50->1:40->2:41->3:21->4:22->1:02->3:12->4:33->4:03->5:34->5:5maxFlow: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  */  


0 0
原创粉丝点击