网络流(学习笔记)

 网络流(学习笔记)

 (PS:本文纯粹复习使用,对于想看图的童鞋不是很友好)

   

  我们想象一下自来水厂到你家的水管网是一个复杂的有向图,每一节水管都有一个最大承载流量。自来水厂不放水,你家就断水了。但是就算自来水厂拼命的往管网里面注水,你家收到的水流量也是上限(毕竟每根水管承载量有限)。你想知道你能够拿到多少水,这就是一种网络流问题。

  这里,我并不喜欢直接扔一大堆定理,比如什么斜对称性啊,流量守恒啊啥啥的,当你学会网络流的基础算法之后,我相信这些都不重要

这里我并没有按照问题的不同而分类,而是就不同的算法来考虑。

  • EK算法(Edmonds Karp算法)

 ——这是一个基于bfs的单路增广算法。

  前置知识:

  网络流里的增广路:如果存在一条路径c(s,t),使得当前的总流量增大,那么这条路径就称为增广路。

  容易发现,如果网络中不存在增广路,那么就能够得到网络流的最大流量。

  那么求最大流问题就转化为求增广路问题,即不断找增广路,直到找不到为止。

  怎样操作呢?我们从s开始bfs,通过残量(边的总容量减去当前流量)大于0的边,每跑到一次t时,我们把改c(s,t)路径上的最小残量找出来,把这条路径灌满:即每一条边都减去这个最小残量。

  这样直到我们发现不存在这样的路径为止。

  那么这里出现了一个疑问:当增广一条路径的时候,你发现另一条路径已经把当前路径上的残量减少,但是从其中的一个点到t仍有可用的残量,这时你会发现,你并不能得到最优解。行吧,这里盗个图:

例如:你已经搜了s->3->5->t,流量是10

你又搜了s->4->5->t,减去第一条路径的流量,新增流量是35

可是你发现,你完全可以搜s->3->t和s->4->5->t,这样流量分别为10,45,显然更大。

可如果你不做任何处理的话,你会发现你在搜过s->3->5->t后,你永远不会再搜到3了,也就不会找到s->3->t这条路径了。

  那么怎么办呢?我们考虑对每条边加一条初始流量为0的反向边。

  当我们先搜s->3->5->t时,我们把正边减去最大流量,反边加上最大流量。

这就告诉了第二条路径s->4->5->t,在到达节点5时,其实有10的流量是通过3留过来的,那么如果把这10流量返回去,再次从3开始跑,若能到达t则相当于找到了一条增广路。进而为第二条路径增大了10残量。

是不是很NB,下面放上code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=10010;
const int maxm=100010;
const int inf=1<<30;

struct node
{
    int to,next,dis;
}g[maxm*2];
int head[maxn],cnt=1; 
struct P
{
    int edge,from;
}pre[maxn];
int ans;
int n,m,s,t;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline void addedge(int u,int v,int dis)
{
    g[++cnt].next=head[u];
    g[cnt].to=v;
    g[cnt].dis=dis;
    head[u]=cnt;
}

bool vis[maxn];
bool bfs()
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    queue<int>q;
    q.push(s);
    vis[s]=1;
    while(q.size())
    {
        int u=q.front();q.pop();
        for(int i=head[u];i;i=g[i].next)
        {
            int v=g[i].to;
            if(!vis[v]&&g[i].dis)
            {
                pre[v].edge=i;
                pre[v].from=u;
                if(t==v)return 1;
                vis[v]=1;
                q.push(v);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/THRANDUil/p/10958237.html
今日推荐