【网络流之最大流算法模板】HDUOJ 3549 Flow Problem

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Jane_JXR/article/details/75073440

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

1、Ford-Fulkerson算法:参见博客详解http://blog.csdn.net/smartxxyx/article/details/9293665/

(1)只利用满足f(e)<c(e)的e或者满足f(e)>0的e对应的反向边rev(e),寻找一条s-t的路径。

(2)如果不存在满足条件的路径,则结束。否则,沿着该路径尽可能地增加流,返回第(1)步。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#define INF 0x3f3f3f3f
typedef long long LL;
using namespace std;
const int maxn=1008;
struct edge
{
    int to,cap,rev;
};
vector<edge>G[maxn];
bool used[maxn];
void addedge(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
}
int dfs(int v,int t,int f)
{
    if(v==t)
        return f;
    used[v]=true;
    for(int i=0;i<G[v].size();i++)
    {
        edge &e=G[v][i];
        if(!used[e.to]&&e.cap>0)
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t)
{
    int flow=0;
    for(;;)
    {
        memset(used,0,sizeof(used));
        int f=dfs(s,t,INF);
        if(f==0)
            return flow;
        flow+=f;
    }
}
int main()
{
    int n,m,x,y,z,t,T=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&m,&n);
        memset(used,false,sizeof(used));
        for(int i=0;i<=m;i++)
            G[i].clear();
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
        }
        int ans=max_flow(1,m);
        printf("Case %d: %d\n",++T,ans);
    }
    return 0;
}

2、Dinic算法:Ford-Fulkerson算法是通过深度优先搜索寻找增广路,并沿着它增广。与之相对,Dinic算法总是寻找最短的增广路,并沿着它增广。因为最短增广路的长度在增广的过程中始终不会变短,所以无需每次都通过宽度预先搜索来寻找最短增广路。我们可以先进行一次宽度优先搜索,然后考虑由近距离顶点指向远距离顶点的所组成的分层图,在上面进行深度优先搜索寻找最短增广路。如果在分层图上找不到新的增广路了,则说明最短增广路的长度确实变长了,或不存在增广路了,于是重新通过宽度优先搜索构造新的分层图。

Dinic算法就是Ford-Fulkerson算法的优化。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define INF 0x3f3f3f3f
typedef long long LL;
using namespace std;
const int maxn=1008;
struct edge
{
    int to,cap,rev;
};
int can[maxn][maxn];
vector<edge>G[maxn];
int level[maxn],n,k;//顶点到源点的距离标号
int iter[maxn];//当前弧,在其之前的边已经没有用了
void addedge(int from,int to,int cap)//向图中增加一条从from到to的容量为cap的边
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
}
void bfs(int s)//通过bfs计算从源点出发的距离标号
{
    memset(level,-1,sizeof(level));
    queue<int>que;
    while(!que.empty())
        que.pop();
    level[s]=0;
    que.push(s);
    while(!que.empty())
    {
        int v=que.front();
        que.pop();
        for(int i=0; i<G[v].size(); i++)
        {
            edge &e=G[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f)//通过dfs寻找增广路
{
    if(v==t||f==0)
        return f;
    for(int &i=iter[v]; i<G[v].size(); i++)
    {
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t)//求解从s-t的最大流
{
    int flow=0;
    for(;;)
    {
        bfs(s);
        if(level[t]<0)
            return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)
        {
            flow+=f;
        }
    }
}
int main()
{
    int t,m,x,y,z,T=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        k=n;
        for(int i=0; i<=n; i++)
            G[i].clear();
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
        }
        int ans=max_flow(1,n);
        printf("Case %d: %d\n",++T,ans);
    }
    return 0;
}

3、Edmonds-Karp算法:算法详解参见博客http://blog.csdn.net/y990041769/article/details/21026445

Edmonds-Karp算法,即最短路径增广算法,简称EK算法。
其思路是每次找出一条从源到汇的能够增加流的路径,调整流值和残留网络 不断调整直到没有增广路为止
增广路: 增广路是这样一条从s到t的路径,路径上每条边残留容量都为正
把残留容量为正的边设为可行的边 那么我们就可以用简单的BFS得到边数最少的增广路
EK算法的思路非常的简单,就是一直找增广路径(BFS),假如有记录增广路的最小值k,ans+=k,并更新网络的值(要用反向边)。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define INF 0x3f3f3f3f
typedef long long LL;
using namespace std;
const int maxn=1008;
struct edge
{
    int from,to,cap,flow;
    edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct edmondskarp
{
    int n,m;
    vector<edge>edges;
    vector<int>mp[maxn];
    int a[maxn];
    int p[maxn];
    void init(int n)
    {
        for(int i=0;i<n;i++)
            mp[i].clear();
        edges.clear();
    }
    void addedge(int from,int to,int cap)
    {
        edges.push_back(edge(from,to,cap,0));
        edges.push_back(edge(to,from,0,0));//反向弧
        m=edges.size();
        mp[from].push_back(m-2);
        mp[to].push_back(m-1);
    }
    int Maxflow(int s,int t)
    {
        int flow=0;
        for(;;)
        {
            memset(a,0,sizeof(a));
            queue<int>q;
            q.push(s);
            a[s]=INF;
            while(!q.empty())
            {
                int x=q.front();
                q.pop();
                for(int i=0;i<mp[x].size();i++)
                {
                    edge& e=edges[mp[x][i]];
                    if(!a[e.to]&&e.cap>e.flow)
                    {
                        p[e.to]=mp[x][i];
                        a[e.to]=min(a[x],e.cap-e.flow);
                        q.push(e.to);
                    }
                }
                if(a[t])
                    break;
            }
            if(!a[t])
                break;
            for(int u=t;u!=s;u=edges[p[u]].from)
            {
                edges[p[u]].flow+=a[t];
                edges[p[u]^1].flow-=a[t];
            }
            flow+=a[t];
        }
        return flow;
    }
};
int main()
{
    int t,n,m,T=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        edmondskarp ac;
        int x,y,z;
        ac.init(n);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            ac.addedge(x,y,z);
        }
        int ans=ac.Maxflow(1,n);
        printf("Case %d: %d\n",++T,ans);
    }
   return 0;
}
题目描述:

Flow Problem

Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 16308    Accepted Submission(s): 7694


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
 

Author
HyperHexagon
 

Source
 

猜你喜欢

转载自blog.csdn.net/Jane_JXR/article/details/75073440