最大流【EK算法】HDU 1532模板题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532

定义:

  1. 网络:网络是一个有向带权图,包含一个源点和一个汇点,没有反向平行边。
  2. 网络流:网络流即网上的流,是定义在网络边集E上的一个非负函数flow={flow(u,v)}, flow(u,v)是边上的流量。
  3. 可行流:满足以下两个性质的网络流flow称为可行流。
    1. 容量约束:每条边的实际流量不能超过改变的最大流量。
    2. 流量守恒:除了源点s和汇点t之外,所有内部节点流入量等于流出量。
  4. 源点s:源点主要是流出,但也有可能流入。
    1. 源点的净输出值=流出量之和-流入量之和。
  5. 汇点t:汇点主要是流入,但也有可能流出。
    1. 汇点的净输入值=流入量之和-流出量之和。
  6. 对于一个网络可行流flow,净输出等于净输入,这仍然是流量守恒。
  7. 网络最大流:在满足容量约束和流量守恒的前提下,在流网络中找到一个净输出最大的网络流。
  8. 增广路算法基本思想:在残留网络中找可增广路,然后在实流网络中沿可增广路增流,在残余网络中沿可增广路减流;继续在残余网络中找可增广路,直到不存在可增广路为止。
  9. 实流网络:实流网络即只显示实际流量的网络。
  10. 残余网络:每个网络G及其上的一个流flow,都对应一个残余网络G’。G’和G的结点集相同,而网络G中的每条边对应G’中的一条边或者两条边。
    1. 在残余网络中,与网络边对应的同向边是可增量(即还可以增加多少流量),反向边是实际流量。
    2. 残余网络没有零流边,因此如果网络中的边实际流量是0,则在残余网络中只对应一条同向边,没有反向边。
    3. 可增广路是残余网络G’中一条从源点s到汇点t的简单路径。
    4. 可增广量是指在可增广路p上每条边可以增加的流量最小值。
  11. 增广路定理:设flow是网络G的一个可行流,如果不存在从源点s到汇点t关于flow的可增广路p,则flow是G的一个最大流。
  12. Edmonds-Karp算法:以广度优先的增广路算法,又称为最短增广路算法(Shortest Augument Panth, SAP)。
  13. 最短增广路算法步骤:采用队列q 来存放已访问未检查的结点。布尔数组vis[]标识结点是否被访问过,pre[]数组记录可增广路上结点的前驱。pre[v]=u 表示可增广路上v 结点的前驱是u,最大流值maxflow=0。
    1. 初始化可行流flow 为零流,即实流网络中全是零流边,残余网络中全是最大容量边(可增量)。初始化vis[]数组为false,pre[]数组为−1。
    2. vis[s]=true,s 加入队列q
    3. 如果队列不空,继续下一步,否则算法结束,找不到可增广路。当前的实流网络就是最大流网络,返回最大流值maxflow
    4. 队头元素new 出队,在残余网络中检查new 的所有邻接结点i。如果未被访问,则访问之,令vis[i]=true,pre[i]=new;如果i=t,说明已到达汇点,找到一条可增广路,转向第(5)步;否则结点i 加入队列q,转向第(3)步。
    5. 从汇点开始,通过前驱数组pre[],逆向找可增广路上每条边值的最小值,即可增量d
    6. 在实流网络中增流,在残余网络中减流,Maxflow+=d,转向第(2)步。

题解:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
const int maxn=1005;
int g[maxn][maxn];
int f[maxn][maxn];
bool vis[maxn];
int pre[maxn];
bool bfs(int s,int t){
    memset(pre,-1,sizeof pre);
    memset(vis,false,sizeof vis);
    queue<int> q;
    vis[s]=true;
    q.push(s);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=1;i<=n;i++){
            if(!vis[i]&&g[now][i]){
                vis[i]=true;
                pre[i]=now;
                if(i==t) return true;
                q.push(i);
            }
        }
    }
    return false;
}
int EK(int s,int t){
    int maxflow=0;
    int u,v;
    while(bfs(s,t)){
        int d=INF;
        v=t;
        while(v!=s){
            u=pre[v];
            if(d>g[u][v])
                d=g[u][v];
            v=u;
        }
        maxflow+=d;
        v=t;
        while(v!=s){
            u=pre[v];
            g[u][v]-=d;
            g[v][u]+=d;
            if(f[v][u]>0)
                f[v][u]-=d;
            else f[u][v]+=d;
            v=u;
        }
    }
    return maxflow;
}
int main()
{
    //int s,t;
    int u,v,c;
    while(~scanf("%d%d",&m,&n)){
        memset(f,0,sizeof f);
        memset(g,0,sizeof g);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&c);
            g[u][v]+=c;
        }
        printf("%d\n",EK(1,n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37867156/article/details/81070103