HDU 3549 Flow Problem

B - Flow Problem
Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph.
 

Input

The first line of input contains an integer T, denoting the number of test cases. 
For each test case, the first line contains two integers N and M, denoting the number of vertexes and edges in the graph. (2 <= N <= 15, 0 <= M <= 1000) 
Next M lines, each line contains three integers X, Y and C, there is an edge from X to Y and the capacity of it is C. (1 <= X, Y <= N, 1 <= C <= 1000)
 

Output

For each test cases, you should output the maximum flow from source 1 to sink N.
 

Sample Input

     
     
2 3 2 1 2 1 2 3 1 3 3 1 2 1 2 3 1 1 3 1
 

Sample Output

     
     
Case 1: 1 Case 2: 2
 

最大流的一些基本概念:

1 流量flow: u->v 的流量为f,则相反方向的v->u的流量为-f

2 容量cap:u->v的容量为c,但v->u的容量为0.(本来图中不存在的边容量都为0)

3 残量cp=容量-流量。cp(u->v)=cap(u->v)-flow(u->v);

4 增广路:在残量图中,一条从起点s到终点t的路径,且该路径上的所以残量的最小值要大于0.

反向边的作用:

反向边相当于一条后悔边,比如说你走了v->u的流量为d,相当于把u->v的流量减少了d

最大流ekrap算法的思想:(其实就是找增广路一步步逼近最大流)

1不停的找增广路,直到没有增广路。

2每找到一条增广路,最大流+=增广路的最大残量值。

3每找到一条增广路,就要更新残量图。(为了方便,我在下面的代码中每次都是更新流量,因为残量=容量-流量,容量不变,知道流量,也就知道了残量)


那么如何找一条从s到t的路径呢?如果随意找,可以用dfs,但是有可能会有特别慢的情况,比如转了好几个弯才到达t。

最好使用bfs找,最慢的时候也是s到t的最短距离。

模板1:dfs

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define maxn 1005
#define inf 0x3f3f3f3f
int first[maxn],nxt[maxn<<1],to[maxn<<1],pre[maxn<<1],e,flow[maxn<<1],cap[maxn<<1];
int a[maxn],fa[maxn];
void add(int u,int v,int c){
     to[e]=v;
     pre[e]=u;
     flow[e]=0;
     cap[e]=c;
     nxt[e]=first[u];
     first[u]=e++;
}
int bfs(int s,int t){
    int f=0;
    fa[s]=-1;
    queue<int>q;
    while(true){
        memset(a,0,sizeof a);
        a[s]=inf;
        q.push(s);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=first[u];~i;i=nxt[i]){
                int v=to[i],c=cap[i],fl=flow[i];
                if(!a[v]&&c-fl>0){
                    q.push(v);
                    fa[v]=i;
                    a[v]=min(a[u],c-fl);
                }
            }
        }
        if(a[t]==0)break;
        int u=t;
        while(fa[u]!=-1){
            int i=fa[u];
            flow[i]+=a[t];
            flow[i^1]-=a[t];
            u=pre[i];
        }
        f+=a[t];
    }
    return f;
}
int main()
{
    int t;
    int n,m;
    int u,v,c;
    int tt=0;
    //freopen("in.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        e=0;
        memset(first,-1,sizeof first);
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&c);
            add(u,v,c);
            add(v,u,0);
        }
        printf("Case %d: %d\n",++tt,bfs(1,n));
    }
}


模板2:bfs


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define maxn 1005
#define inf 0x3f3f3f3f
int first[maxn],nxt[maxn<<1],to[maxn<<1],pre[maxn<<1],e,flow[maxn<<1],cap[maxn<<1];
int a[maxn],fa[maxn];
bool vis[maxn];
void add(int u,int v,int c){
     to[e]=v;
     pre[e]=u;
     flow[e]=0;
     cap[e]=c;
     nxt[e]=first[u];
     first[u]=e++;
}
int dfs(int u,int t){                                //这是错误的写法,不要被误导
    if(u==t)return inf;
    vis[u]=1;
     for(int i=first[u];~i;i=nxt[i]){
        int v=to[i];
        if(!vis[v]&&cap[i]-flow[i]>0){
          int d=min(cap[i]-flow[i],dfs(v,t));          //错误,最底层返回就要知道最小是多少了。不能全部返回完才知道
          if(d>0){                                     //如果这样写,就得和bfs一样的记录路径的写法
            flow[i]+=d;
            flow[i^1]-=d;
            return d;
          }
        }
     }
     return 0;
}
int dfs1(int u,int t,int f){
   if(u==t)return f;
    vis[u]=1;
     for(int i=first[u];~i;i=nxt[i]){
        int v=to[i];
        if(!vis[v]&&cap[i]-flow[i]>0){
          int d=dfs1(v,t,min(f,cap[i]-flow[i]));
          if(d>0){
            flow[i]+=d;
            flow[i^1]-=d;
            return d;
          }
        }
     }
     return 0;
}
int max_flow(int s,int t){
    int flow=0;
    while(1){
        memset(vis,0,sizeof vis);
        int f=dfs1(s,t,inf);
        if(f==0)return flow;
        flow+=f;
    }
}
int main()
{
    int t;
    int n,m;
    int u,v,c;
    int tt=0;
    //freopen("in.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        e=0;
        memset(first,-1,sizeof first);
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&c);
            add(u,v,c);
            add(v,u,0);
        }
        printf("Case %d: %d\n",++tt,max_flow(1,n));
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值