最大流的增广路模板


假设从s到t之间所有路径的容量如下图的有向图

                                                      

                    

如果走s->1->2->t,则这条路径能传输的流量是5。
接着走s->1->3->t,因为 s->1的容量为10,则这次只能传输5,所以按照这种方法从s到t能传输的总流量为10。

用cf[][]数组存储从A->B点的容量
按照上述方法,从1->2的流量为f=5,则将cf[1][2]-=5,此时1->2的残流(即剩余容量)为1,此时反向边2->1的容量
加5,因原本2->1的流量为0,此时c[2][1]=5。
假设所有路径已经结束,此时,cf[1][2]=1,cf[2][1]=5,cf[1][3]=1,cf[3][1]=5
若从2点向1点发出流量,而此时cf[1][2]这条路径为1,找到各个路径中大于0的最小残流量为1,
而在2->1->3->t这条路径中,还可以再多承载1的流量,此时cf[1][2]=4(因为由2向1逆推了1的流量),cf[1][3]=6,
cf[3][t]=6,而此时cf[2][1]=6,cf[2][t]=4.


现在再来观察这张图

                                      

                            

此时我们可以发现s->2->t这条路仍旧可以走,此时cf[2][t]=4,未饱和,找到此时路径中的最小残流量为1,
从s向2发出1的流量,这时cf[2][t]这条路径饱和,这时候可以发现,从s到t可以传输的总流量为11




/***********************************************************/

BFS(Edmonds_Karp算法)

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f

int f,flow[210][210],cap[210][210],a[210];
int m,n,p[210];

void bfs()
{
    int s=1;
    f=0;
    queue<int>q;
    for(;;)
    {
        memset(a,0,sizeof(a));
        a[s]=INF;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int v=1; v<=n; v++)
            {
                if(!a[v] && cap[u][v] > flow[u][v])
                {
                    a[v]=min(a[u],cap[u][v]-flow[u][v]);
                    p[v]=u;  //记录v的父亲,并加入队列
                    q.push(v);
                }
            }
        }
        if(a[n]==0)//若找不到说明已经是最大流
            break;
        for(int i=n; i!=s; i=p[i]) //从汇点逆行
        {
            flow[p[i]][i]+=a[n];  //更新正向流量
            flow[i][p[i]]-=a[n]; //更新反向流量
        }
        f+=a[n];
    }
}

int main()
{
    int a,b,c;
    while(~scanf("%d%d",&m,&n))
    {
        memset(flow,0,sizeof(flow));
        memset(cap,0,sizeof(cap));
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            cap[a][b]+=c;
        }
        bfs();
        printf("%d\n",f);
    }
    return 0;
}


/*********************************************************************************/

DFS模板(书上的)


#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f

struct edge  //用于表示边的结构体(终点,容量,反向边)
{
    int to,cap,rev;
};
vector<edge> G[201];
int book[201];

int dfs(int v,int t,int f)  //通过DFS寻找增广路
{
    if(v==t)
        return f;
    book[v]=1;
    for(int i=0; i<G[v].size(); i++)
    {
        edge &e=G[v][i];
        if(!book[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)  //求解从s到t的最大流
{
    int flow=0;
    for(;;)
    {
        memset(book,0,sizeof(book));
        int f=dfs(s,t,INF);
        if(f==0)
            return flow;
        flow+=f;
    }
}

int main()
{
    int n,m;
    int from,to,cap;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1; i<=m; i++)
            G[i].clear();
        for(int i=0; i<n; i++)
        {
            scanf("%d%d%d",&from,&to,&cap);
            G[from].push_back((edge)
            {
                to,cap,G[to].size()     //G[to].size()指反向边存放的位置
            });

            G[to].push_back((edge)
            {
                from,0,G[from].size()-1
            });
        }
        printf("%d\n",max_flow(1,m));
    }
    return 0;
}


/*******************************************************************/
DFS(在网上看到的大牛写的代码)


#include<cstdio>
#include<cstring>
#define N 201
 
 
int n; //有向边数
int m; //顶点数
int f[N][N]; //网络流
int cf[N][N]; //残留网络
bool vis[N]; //DFS中是否访问过
 
 
const int inf =1<<29;
 
 
 
 
int inline min(intx,int y)
{
    return x>y?y:x;
}
 
 
bool dfs(int s,intt,int &cf_path)
{
    vis[s]=true;
    if(s==t)
        return true;
 
 
    for(int i=1; i<=m; ++i)
    {
        if(vis[i]==false &&cf[s][i]>0)
        {
            int temp = cf_path;
 
 
            cf_path=min(cf_path,cf[s][i]);//(a)式
            if(dfs(i,t,cf_path))
            {
                f[s][i]+=cf_path; //更新发出的总流量,因为发出的和收到的总是相等的
 
 
                cf[s][i]-=cf_path;
                cf[i][s]+=cf_path; //允许“反悔”
                return true;
            }
 
 
//沿着<s,i>向下深搜失败,回溯时恢复增广路径的残留容量cf[path];
//实际上是在撤销(a)式的影响!
            cf_path = temp;
        }
    }
    return false;
}
 
 
int find(int s=1,intt=m) //这实际上是DFS的外围框架(回忆DFS算法实现有内外两层)
{
    int cf_path = inf; //本次可增广的流量,在DFS过程中被限制得越来越小
    memset(vis,0,sizeof(vis));
 
 
    dfs(s,t,cf_path);
 
 
    if(cf_path>=inf)
        return 0;
    else
        return cf_path;
}
 
 
int max_flow()
{
    int ret=0,i;
    memset(f,0,sizeof(f));
    while(find());
 
 
    for(i=1; i<=m; ++i)
        ret+=f[1][i]; //网络流的值=从源出发的流量和f(s,V)=流入汇点的流量和f(V,t)
    return ret;
}
 
 
int main(void)
{
    int i,x,y,z;
   while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(cf,0,sizeof(cf));
        for(i=0; i<n; ++i)
        {
           scanf("%d%d%d",&x,&y,&z);
            cf[x][y]+=z;
        }
        printf("%d\n",max_flow());
    }
    return 0;
}








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值