zoukankan      html  css  js  c++  java
  • hihoCoder1369 (最大流EK算法,Dinic算法)Ford-Fulkerson

    #1369 : 网络流一·Ford-Fulkerson算法

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    小Hi和小Ho住在P市,P市是一个很大很大的城市,所以也面临着一个大城市都会遇到的问题:交通拥挤。

    小Ho:每到周末回家感觉堵车都是一种煎熬啊。

    小Hi:平时交通也还好,只是一到上下班的高峰期就会比较拥挤。

    小Ho:要是能够限制一下车的数量就好了,不知道有没有办法可以知道交通系统的最大承受车流量,这样就可以限制到一个可以一直很顺畅的数量了。

    小Hi:理论上是有算法的啦。早在1955年,T.E.哈里斯就提出在一个给定的网络上寻求两点间最大运输量的问题。并且由此产生了一个新的图论模型:网络流

    小Ho:那具体是啥?

    小Hi:用数学的语言描述就是给定一个有向图G=(V,E),其中每一条边(u,v)均有一个非负数的容量值,记为c(u,v)≥0。同时在图中有两个特殊的顶点,源点S和汇点T。

    举个例子:

    其中节点1为源点S,节点6为汇点T。

    我们要求从源点S到汇点T的最大可行流量,这个问题也被称为最大流问题

    在这个例子中最大流量为5,分别为:1→2→4→6,流量为1;1→3→4→6,流量为2;1→3→5→6,流量为2。

    小Ho:看上去好像挺有意思的,你让我先想想。

    输入

    第1行:2个正整数N,M。2≤N≤500,1≤M≤20,000。

    第2..M+1行:每行3个整数u,v,c(u,v),表示一条边(u,v)及其容量c(u,v)。1≤u,v≤N,0≤c(u,v)≤100。

    给定的图中默认源点为1,汇点为N。可能有重复的边。

    输出

    第1行:1个整数,表示给定图G的最大流。

    样例输入
    6 7
    1 2 3
    1 3 5
    2 4 1
    3 4 2
    3 5 3
    4 6 4
    5 6 2
    样例输出
    5

    分析:hiho的提示讲得很清楚,EK算法或者Dinic算法求最大流。

    Edmond-Karp算法的代码:(88ms)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define INF 999999999
    using namespace std;
    int N,M;//N个点M条边
    int p[502],map[503][503];
    bool vis[502];//标记数组 
    int EK()
    {
        int ans=0;//ans表示最大流,初始化为0 
        while(true)
        {
            queue<int> q;//寻找增广路 
            memset(p,-1,sizeof(p));
            memset(vis,false,sizeof(vis));
            q.push(1);vis[1]=true;
            while(!q.empty())
            {
                int u=q.front();
                if(u==N) break;
                q.pop();
                for(int i=1;i<=N;i++)
                {
                    if(map[u][i]&&!vis[i])//当前边容量非零,且增广点未标记 
                    {
                        vis[i]=true;
                        p[i]=u;//记录点i的前一个结点v
                        q.push(i); 
                    }
                }
            }
            if(p[N]==-1) break;//没有找到增广路 
            int k=N,MAX=INF;//MAX为增广路中的最大流 
            while(p[k]!=-1)
            {
                MAX=min(MAX,map[p[k]][k]);
                k=p[k];
            }
            ans+=MAX;//累加进最大流 
            
            k=N;//修改路径上的边容量 
            while(p[k]!=-1)
            {
                map[p[k]][k]-=MAX;
                map[k][p[k]]+=MAX;
                k=p[k];
            }
        }
        return ans;
    }
    
    
    int main()
    {
        scanf("%d%d",&N,&M);
        for(int i=0;i<M;i++)
        {
            int s,t,c;
            scanf("%d%d%d",&s,&t,&c);
            map[s][t]+=c;
        }
        printf("%d
    ",EK());
        return 0;
    }
    View Code

    Dinic算法的代码:(26ms)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define INF 999999999
    using namespace std;
    int N,M;//N个点M条边 
    int map[502][502];
    int dis[502];//分层 
    
    int bfs()//分层 
    {
        memset(dis,-1,sizeof(dis));
        dis[1]=0;
        queue<int> q;
        q.push(1);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=1;i<=N;i++)
            if(dis[i]==-1&&map[u][i]>0)
            {
                dis[i]=dis[u]+1;
                q.push(i);
            }
        }
        if(dis[N]>0) return 1;
        return 0;//无法遍历到汇点则返回0退出 
    } 
    
    int dfs(int cur,int m)//m为当前流量上限,即从点cur流出的流量最多为m 
    {
        if(cur==N) return m;
        int f,res=0;
        for(int i=1;i<=N;i++)
        {
            if(dis[i]==dis[cur]+1&&map[cur][i]>0&&(f=dfs(i,min(m,map[cur][i]))))
            {
                map[cur][i]-=f;
                map[i][cur]+=f;//修改路径上的边容量 
                res+=f;
                m-=f;//每找到增广路便修改流量上限 
                if(!m) break;//流量上限为0就退出循环 
            }
        }
        if(res) return res;
        dis[cur]=-1;//res==0的时候这个结点不能流通,即通过该结点找不到增广路 
        return 0;
    }
    
    int main()
    {
        scanf("%d%d",&N,&M);
        for(int i=0;i<M;i++)
        {
            int s,t,c;
            scanf("%d%d%d",&s,&t,&c);
            map[s][t]+=c;
        }
        int ans=0,res;//res为增广路的残余流量 
        while(bfs())
        {
            while(res=dfs(1,INF))
            ans+=res;
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    Dinic算法(数组模拟邻接链表):(17ms)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define INF 999999999
    #include<queue>
    using namespace std;
    int N,M,cnt;//cnt为边的数量 
    struct Node{
        int s,t,c;
    }edge[50000];//边数是M的最大值的两倍 
    int head[502],next1[50000];
    int dis[502];
    
    void add(int s,int t,int c)
    {
        edge[cnt].s=s;
        edge[cnt].t=t;
        edge[cnt].c=c;
        next1[cnt]=head[edge[cnt].s];
        head[edge[cnt].s]=cnt++;
    }
    
    int bfs()
    {
        memset(dis,-1,sizeof(dis));
        dis[1]=0;
        queue<int> q;
        q.push(1);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            int k=head[u];
            while(k!=-1)
            {
                int v=edge[k].t;
                if(dis[v]==-1&&edge[k].c>0)
                {
                    dis[v]=dis[u]+1;
                    q.push(v);
                }
                k=next1[k];
            }
        }
        if(dis[N]>0) return 1;
        return 0;
    }
    
    int dfs(int cur,int m)
    {
        if(cur==N) return m;
        int res=0,f,k=head[cur];
        while(k!=-1)
        {
            if(dis[edge[k].t]==dis[cur]+1&&edge[k].c>0&&(f=dfs(edge[k].t,min(m,edge[k].c))))
            {
                edge[k].c-=f;
                edge[k^1].c+=f;
                res+=f;
                m-=f;
                if(!m) break;
            }
            k=next1[k];
        }
        if(res) return res;
        dis[cur]=-1;
        return 0;
    }
    
    int main()
    {
        scanf("%d%d",&N,&M);
        memset(head,-1,sizeof(head));
        cnt=0;
        for(int i=0;i<M;i++)
        {
            int s,t,c;
            scanf("%d%d%d",&s,&t,&c);
            add(s,t,c);
            add(t,s,0);
        }
        int ans=0,res;
        while(bfs())
            while(res=dfs(1,INF)) ans+=res;
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    LeetCode 275. H-Index II
    LeetCode 274. H-Index
    LeetCode Gray Code
    LeetCode 260. Single Number III
    LeetCode Word Pattern
    LeetCode Nim Game
    LeetCode 128. Longest Consecutive Sequence
    LeetCode 208. Implement Trie (Prefix Tree)
    LeetCode 130. Surrounded Regions
    LeetCode 200. Number of Islands
  • 原文地址:https://www.cnblogs.com/ACRykl/p/8783211.html
Copyright © 2011-2022 走看看