• hdu 3549 Flow Problem(最大流入门)


    Problem 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
    解题思路:Dicic实现,即每个阶段先进行1次bfs给图分层,然后在该图上进行1次或多次寻找增广路,如果当前层次图中已找不到增广路,就重新给图分层,然后继续找增广路,只要t的level小于0就说明当前网络已达到最大流。时间复杂度大概为O(|E||V|2)。
    AC代码一(312ms):
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int INF=0x3f3f3f3f;
     4 const int maxn=1005;//int cnt=1;
     5 struct edge{ int to, cap; size_t rev;
     6     edge(int _to, int _cap, size_t _rev) :to(_to), cap(_cap), rev(_rev){}//构造函数,初始化结构体变量
     7 };//指向节点to,边容量是cap,rev是记录为当前邻接点to反向边的编号
     8 vector<edge> G[maxn];//邻接表,G[i][j]表示节点i连接的第j条边包含的所有信息
     9 int t,n,m,x,y,c,level[maxn];//level数组在bfs时为分层图所用
    10 void add_edge(int from,int to,int cap){//向图中增加一条从s到t容量为cap的边
    11     G[from].push_back(edge( to, cap, G[to].size() ));
    12     G[to].push_back(edge( from, 0, G[from].size() - 1));//关键:反向建边,初始流量为0
    13 }
    14 //bfs给图分层次
    15 void bfs(int s){
    16     memset(level,-1,sizeof(level));//刚开始每个节点的层次置为-1
    17     queue<int> que;//队列实现bfs
    18     level[s]=0;//源点s为第0层
    19     que.push(s);
    20     while(!que.empty()){//给图分层
    21         int v=que.front();que.pop();
    22         for(size_t i=0;i<G[v].size();++i){//遍历节点v与之相连的每条边
    23             edge &e=G[v][i];//取出与节点v相连的第i条边
    24             if(e.cap>0&&level[e.to]<0){//如果边残余流量大于0,且节点e.to还未分层
    25                 level[e.to]=level[v]+1;//节点e.to的层次为指向它的节点v所在层次数加1
    26                 que.push(e.to);
    27             }
    28         }
    29     }
    30 }
    31 //dfs寻找增广路,寻找当前图中s-->t的一条增广路
    32 int dfs(int v,int t,int f){//v->t(t为汇点),当前增广路径上的最小剩余流量为f
    33     if(v==t)return f;//到达汇点t
    34     for(size_t i=0;i<G[v].size();++i){//遍历节点v与之相连的每条边
    35         edge &e=G[v][i];//取出与节点v相连的第i条边
    36         if(e.cap>0 && level[v]<level[e.to]){//如果该边残流量大于0,且邻接点e.to是v的下一级,就增广下去
    37             //cout<<"当前遍历到的点v:"<<v<<",邻接点to:"<<e.to<<endl;
    38             int d=dfs(e.to,t,min(f,e.cap));//维护当前增广路上最小的剩余流量f
    39             if(d>0){//若f>0,说明找到了一条增广路
    40                 //cout<<v<<"-->"<<e.to<<",边容量为:"<<e.cap<<endl;
    41                 e.cap-=d;//正向边流量减去f
    42                 G[e.to][e.rev].cap+=d;//反向边流量加上f
    43                 return d;//沿着增广路回溯到源点s,不会在途中去深搜其他点,返回当前增广路上的最小剩余流量
    44             }
    45         }
    46     }
    47     return 0;//否则说明没有增广路,返回0
    48 }
    49 //Dinic算法实现最大流,每个阶段执行完一次bfs分层之后,只需查找当前层次图中是否还增广路即可
    50 int max_flow(int s,int t){
    51     int flow=0;
    52     while(1){
    53         bfs(s);//每个阶段先bfs将图分层标记
    54         if(level[t]<0)return flow;
    55         //如果分层之后,汇点t的层次小于0,即未被分层,说明再无增广路,则直接返回当前最大流量
    56         int f=dfs(s,t,INF);
    57         //cout<<"第"<<cnt++<<"次的最小剩余容量为:"<<f<<endl;
    58         while(f>0){//在该层次图中找到增广路
    59             flow+=f;//累加到最大流中
    60             f=dfs(s,t,INF);//继续找该层次图中是否还有增广路,直到f为0,
    61             //cout<<"第"<<cnt++<<"次的最小剩余容量为:"<<f<<endl;
    62         }
    63     }
    64 }
    65 int main(){
    66     while(~scanf("%d",&t)){
    67         for(int cas=1;cas<=t;++cas){
    68             scanf("%d%d",&n,&m);//cnt=1;
    69             for(int i=0;i<=n;++i)G[i].clear();
    70             while(m--){
    71                 scanf("%d%d%d",&x,&y,&c);
    72                 add_edge(x,y,c);
    73             }
    74             printf("Case %d: %d
    ",cas,max_flow(1,n));
    75         }
    76     }
    77     return 0;
    78 }

    AC代码二(93ms):当前弧优化Dinic算法。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int INF=0x3f3f3f3f;
     4 const int maxn=1005;
     5 struct edge{ int to,cap;size_t rev;
     6     edge(int _to, int _cap, size_t _rev):to(_to),cap(_cap),rev(_rev){}
     7 };
     8 int T,n,m,x,y,c,level[maxn];queue<int> que;vector<edge> G[maxn];size_t curfir[maxn];
     9 void add_edge(int from,int to,int cap){
    10     G[from].push_back(edge(to,cap,G[to].size()));
    11     G[to].push_back(edge(from,0,G[from].size()-1));
    12 }
    13 bool bfs(int s,int t){
    14     memset(level,-1,sizeof(level));
    15     while(!que.empty())que.pop();
    16     level[s]=0;
    17     que.push(s);
    18     while(!que.empty()){
    19         int v=que.front();que.pop();
    20         for(size_t i=0;i<G[v].size();++i){
    21             edge &e=G[v][i];
    22             if(e.cap>0&&level[e.to]<0){
    23                 level[e.to]=level[v]+1;
    24                 que.push(e.to);
    25             }
    26         }
    27     }
    28     return level[t]<0?false:true;
    29 }
    30 int dfs(int v,int t,int f){
    31     if(v==t)return f;
    32     for(size_t &i=curfir[v];i<G[v].size();++i){
    33         edge &e=G[v][i];
    34         if(e.cap>0&&(level[v]+1==level[e.to])){
    35             int d=dfs(e.to,t,min(f,e.cap));
    36             if(d>0){
    37                 e.cap-=d;
    38                 G[e.to][e.rev].cap+=d;
    39                 return d;
    40             }
    41         }
    42     }
    43     return 0;
    44 }
    45 int max_flow(int s,int t){
    46     int f,flow=0;
    47     while(bfs(s,t)){
    48         memset(curfir,0,sizeof(curfir));
    49         while((f=dfs(s,t,INF))>0)flow+=f;
    50     }
    51     return flow;
    52 }
    53 int main(){
    54     while(~scanf("%d",&T)){
    55         for(int cas=1;cas<=T;++cas){
    56             scanf("%d%d",&n,&m);
    57             for(int i=0;i<=n;++i)G[i].clear();
    58             while(m--){
    59                 scanf("%d%d%d",&x,&y,&c);
    60                 add_edge(x,y,c);
    61             }
    62             printf("Case %d: %d
    ",cas,max_flow(1,n));
    63         }
    64     }
    65     return 0;
    66 }
  • 相关阅读:
    要么优秀,要么负责阅读作业二感想
    Python核心编程学习日记之数字,序列
    Python核心编程学习日记之错误处理
    Python核心编程学习日记之语法和对象
    Innobakcupex 代码解析
    通过initconnect + binlog 实现MySQL审计功能
    关于Relay Log无法自动删除的问题
    MySQL中 timeout相关参数解析
    慢查询日志中出现超大时间的案例分析
    主键乱序插入对Innodb性能的影响
  • 原文地址:https://www.cnblogs.com/acgoto/p/9845914.html
Copyright © 2020-2023  润新知