您的位置:首页 > 其它

poj 1273 最大流(Ford-Fulkerson算法和Dinic算法分别实现)

2014-07-10 16:45 441 查看
最大流模板题目

Ford-Fulkerson:

#include <stdio.h>
#include <string.h>
#define N 202
int q
;//用于找增广路径的队列
int c

,f

;//c是路径的容量,f保存寻找过程中的流量
int a
,p
;//p存放一条增广路径的前一个结点
int n,m;
int maxflow(int s,int t){//从s到t的最大流
int i,j,res = 0;
int front,rear;
while(1){
front = rear = -1;
q[++rear] = s;
memset(a,0,sizeof(a));
memset(p,0,sizeof(p));
a[s] = 0x3fffffff;
while(front < rear){
i = q[++front];
for(j = 1;j<=n;j++)
if(!a[j] && c[i][j]-f[i][j]>0){
a[j] = a[i]<c[i][j]-f[i][j]?a[i]:c[i][j]-f[i][j];
q[++rear] = j;
p[j] = i;
}
}
if(!a[t])
break;
for(j = t;j!=s;j=p[j]){
f[p[j]][j] += a[t];
f[j][p[j]] -= a[t];
}
res += a[t];
}
return res;
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d %d",&m,&n)!=EOF){
int i,x,y,w;
memset(c,0,sizeof(c));
memset(f,0,sizeof(f));
for(i = 0;i<m;i++){
scanf("%d %d %d",&x,&y,&w);
c[x][y] += w;
}
printf("%d\n",maxflow(1,n));
}
return 0;
}


Dinic求最大流的过程:先利用 BFS对残余网络分层,此后从源点开始,用DFS从前一层向后一层反复寻找增广路(即要求DFS的每一步都必须要走到下一层的节点)。

(因此前面在分层时,只要进行到汇点的层次数被算出即可停止,因为按照该DFS的规则,和汇点同层或更下一层的节点,是不可能走到汇点的。)

DFS过程中,要是碰到了汇点,则说明找到了一条增广路径。此时要增加总流量的值,消减路径上各边的容量,并添加反向边,即进行增广。然后进行顶点回溯,到第一条仍有容量的边的顶点处继续找增广路。如果回溯到源点而且无法继续往下走了,DFS结束。

因此,一次DFS过程中,可以找到多条增广路径。DFS结束后,对残余网络再次进行分层,重复上述步骤。

当残余网络的分层操作无法算出汇点的层次(即BFS到达不了汇点)时,算法结束,最大流求出。一般用栈实现DFS,这样就能从栈中提取出增广路径。

#include <stdio.h>
#include <string.h>
#define INF 0x3fffffff
#define min(a,b) a<b?a:b
#define N 205
int n,m;
int flow

,visited
,layer
,q
,stack
;
int do_layer(int s,int t){//用队列对节点进行分层
int i,front,rear,now;
front = rear = -1;
memset(layer,-1,sizeof(layer));
q[++rear] = s;
layer[s] = 0;
while(front < rear){
now = q[++front];
for(i = s;i<=t;i++)
if(layer[i]==-1 && flow[now][i]>0){
layer[i] = layer[now]+1;
if(i == t)
return 1;
q[++rear] = i;
}
}
return 0;
}
int dinic(int s,int t){//用堆栈模拟dfs
int i,now,top=-1,aug,res=0,temp,vs,vt;
while(do_layer(s,t)){
memset(visited,0,sizeof(visited));
stack[++top] = s;
visited[s] = 1;
while(top>-1){
now = stack[top];
if(now == t){
aug = INF;temp = 0;//temp保存回溯的位置
for(i = 1;i<=top;i++){//找本次增广的流量
vs = stack[i-1];
vt = stack[i];
if(aug>flow[vs][vt] && flow[vs][vt]>0){
aug = min(aug,flow[vs][vt]);
temp = vs;
}
}
res += aug;
for(i = 1;i<=top;i++){//更新流量以及反向边
vs = stack[i-1];
vt = stack[i];
flow[vs][vt] -= aug;
flow[vt][vs] += aug;
}
while(stack[top]!=temp){
visited[stack[top]] = 0;
top--;
}
}else{
for(i = s;i<=t;i++)
if(!visited[i] && flow[now][i]>0 && layer[i]==layer[now]+1){
stack[++top] = i;
visited[i] = 1;
break;
}
if(i > t)
top--;
}
}
}
return res;
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d %d",&m,&n)!=EOF){
int i,a,b,w;;
memset(flow,0,sizeof(flow));
for(i = 0;i<m;i++){
scanf("%d %d %d",&a,&b,&w);
flow[a][b] += w;
}
printf("%d\n",dinic(1,n));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: