zoukankan      html  css  js  c++  java
  • 【模板】网络最大流(EK算法)

    网络流EK算法主要是以bfs为主,寻找一条增广路。

    增广路算法的关键是 寻找增广路 和 改进网络流。
    1. bfs判断由从源点到汇点是否联通,并寻找到这条增广路;
    2. 更新路径上的流量,正向边减去流量,反向弧加上流量;
    3. 重复执行1过程,直到找不到增广路。

    不懂是吗,其实我也不懂为啥要加反向边

    创建反向弧是因为在其他增广路要经过这条路径时,要将此路径上的流量反推过去,实现流量最大化。

    emmm,我知道其实自己说的很绕。。。 但是多读读下面的模板代码应该就能理解,毕竟我又不擅长写那种难以读懂的代码。

    邻接矩阵实现

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define ms(n,x) memset(n,x,sizeof(n))
    using namespace std;
    const int MAXN = 300;
    const int MAX_INT = ((1 << 30) - 1);
    
    int s,t;
    int n,m;
    bool vis[MAXN];
    int pre[MAXN];
    int mp[MAXN][MAXN];
    
    bool bfs(int s,int t)
    {
        queue <int> que;
        ms(vis,0);
        ms(pre,-1);
        que.push(s);
        vis[s]=true;
        pre[s]=s;
        while(!que.empty())
        {
            int u=que.front();
            que.pop();
            for(int i=1;i<=n;i++)
            {
                if(mp[u][i]&&!vis[i])
                {
                    vis[i]=true;
                    pre[i]=u;
                    if(i==t)
                        return true;
                    que.push(i);
                }
            }
        }
        return false;
    }
    int EK()
    {
        int ans=0;
        while(bfs(s,t))
        {
            int mi=MAX_INT;
            for(int i=t;i!=s;i=pre[i])
            {
                mi=min(mi,mp[pre[i]][i]);
            }
            for(int i=t;i!=s;i=pre[i])
            {
                mp[pre[i]][i]-=mi;
                mp[i][pre[i]]+=mi;
            }
            ans+=mi;
        }
        return ans;
    }
    int main()
    {
    
        scanf("%d%d",&n,&m);
        scanf("%d%d",&s,&t);
        ms(mp,0);
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            mp[x][y]=z;
        }
        printf("%d
    ",EK());
        return 0;
    }
    
    /*
    
    6 7
    1 6
    1 2 2
    1 3 1
    3 4 1
    2 5 1
    2 4 2
    4 6 2
    5 6 1
    
    */

    邻接表实现

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define ms(n,x) memset(n,x,sizeof(n))
    using namespace std;
    
    struct Edge
    {
        int to,next,weigh;
    };
    struct Node
    {
        int from,id;
    };
    
    const int MAXN = 10005;
    const int MAXM = 100005*2;
    const int MAX_INT = (1<<30);
    
    Edge edge[MAXM];
    Node pre[MAXM];
    int head[MAXM];
    bool vis[MAXM];
    int n,m,s,t,cont;
    
    void init()
    {
        cont=0;
        ms(edge,0);
        ms(head,-1);
    }
    void addedge(int from,int to,int weigh)
    {
        edge[cont].to=to;
        edge[cont].weigh=weigh;
        edge[cont].next=head[from];
        head[from]=cont++;
    }
    bool bfs(int s,int t)
    {
        queue<int> que;
        ms(pre,-1);
        ms(vis,0);
        pre[s].from=s;
        vis[s]=true;
        que.push(s);
        while(!que.empty())
        {
            int u=que.front();
            que.pop();
            for(int i=head[u];i+1;i=edge[i].next)
            {
                int from=edge[i].to;
                if(!vis[from]&&edge[i].weigh)
                {
                    pre[from].from=u;
                    vis[from]=true;
                    pre[from].id=i;
                    if(from==t)
                        return true;
                    que.push(from);
                }
            }
        }
        return false;
    }
    
    int EK()
    {
        int ans=0;
        while(bfs(s,t))
        {
            int mi=MAX_INT;
            for(int i=t;i!=s;i=pre[i].from)
            {
                mi=min(mi,edge[pre[i].id].weigh);
            }
            for(int i=t;i!=s;i=pre[i].from)
            {
                edge[pre[i].id].weigh-=mi;
                edge[pre[i].id^1].weigh+=mi;
            }
            ans += mi;
        }
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        scanf("%d%d",&s,&t);
        init();
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
            addedge(y,x,0);
        }
        printf("%d
    ",EK());
        return 0;
    }

    模板由此理解: https://blog.csdn.net/txl199106/article/details/64441994

  • 相关阅读:
    [20170612]FOR ALL COLUMNS SIZE repeat(11g).txt
    [20170612]FOR ALL COLUMNS SIZE repeat(12c).txt
    [20170611]关于数据块地址的计算.txt
    [20170607]再论Private Strand Flush Not Complete.txt
    [20170606]11G _optimizer_null_aware_antijoin.txt
    42_自定义泛型类的应用
    43_通过反射获得泛型的实际类型参数
    为什么好男孩找不到女朋友
    38_泛型的通配符扩展应用
    36_入门泛型的基本应用
  • 原文地址:https://www.cnblogs.com/Whiteying/p/10072962.html
Copyright © 2011-2022 走看看