[Graph]网络流——Dinic

网络流.Dinic

定义:

源点:只有流出去的点
汇点:只有流进来的点
流量:一条边上流过的流量
容量:一条边上可供流过的最大流量
残量:一条边上的容量-流量

性质:

对于任何一条流,总有流量<=容量

pEk[p][u]==qEk[u][q](其中k[i][j]表示i到j的流量)

对于任何一条有向边有 k[u][v]=-k[v][u](k为流量)


 

网络最大流算法

基本思路:

找到一条从源点到汇点的路径,使得路径上任意一条边的残量>0,这条路径便称为增广路

找到这条路径上最小的F[u][v](我们设F[u][v]表示u->v这条边上的残量即剩余流量),下面记为flow
将这条路径上的每一条有向边u->v的残量减去flow,同时对于起反向边v->u的残量加上flow
重复上述过程,直到找不出增广路,此时我们就找到了最大流

反向边提供了反悔的机会,即万一这条路不是最优解,在下一次BFS时可以搜到这条反向边,返回原点。

Dinic的层次图为每个点提供了一个深度,加快了找到最大流的速度。

int bfs()
        {
            //cout<<"Bfs.begin:"<<endl;
            queue<int> Q;
            while (!Q.empty())
                Q.pop();
            memset(Depth,0,sizeof(Depth));
            Depth[s]=1;
            Q.push(s);
            do
            {
                int u=Q.front();
                //cout<<u<<endl;
                Q.pop();
                for (int i=Head[u];i!=-1;i=Next[i])
                {
                    if ((W[i]>0)&&(Depth[V[i]]==0))
                    {
                        Depth[V[i]]=Depth[u]+1;
                        Q.push(V[i]);
                    }
                }
            }
            while (!Q.empty());
            //cout<<"Bfs.end"<<endl;
            if (Depth[t]>0)
                return 1;
            return 0;
        }
BFS
int dfs(int u,int dist)
        {
            //cout<<"Dfs:"<<u<<' '<<dist<<endl;
            if (u==t)
                return dist;
            for (int i=Head[u];i!=-1;i=Next[i])
            {
                if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0))
                {
                    int di=dfs(V[i],min(dist,W[i]));
                    if (di>0)
                    {
                        W[i]-=di;
                        W[i^1]+=di;
                        return di;
                    }
                }
            }
            return 0;
        }
DFS
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define maxM 200010
#define maxN 100010
#define inf 2e9
    int s,t;
    int cnt;
    int Head[maxM];
    int Next[maxM];
    int V[maxM];
    int W[maxM];
    int Depth[maxN];
    int n;
    void init(int nn,int ss,int tt)//初始化
        {
            n=nn;
            s=ss;
            t=tt;
            cnt=-1;
            memset(Head,-1,sizeof(Head));
            memset(Next,-1,sizeof(Next));
            return;
        }
    void _Add(int u,int v,int w)
        {
            cnt++;
            Next[cnt]=Head[u];
            V[cnt]=v;
            W[cnt]=w;
            Head[u]=cnt;
        }
    void Add_Edge(int u,int v,int w)//加边,同时加正向和反向的
        {
            _Add(u,v,w);
            _Add(v,u,0);
        }
    int dfs(int u,int dist)
        {
            //cout<<"Dfs:"<<u<<' '<<dist<<endl;
            if (u==t)
                return dist;
            for (int i=Head[u];i!=-1;i=Next[i])
            {
                if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0))
                {
                    int di=dfs(V[i],min(dist,W[i]));
                    if (di>0)
                    {
                        W[i]-=di;
                        W[i^1]+=di;
                        return di;
                    }
                }
            }
            return 0;
        }
    int bfs()
        {
            //cout<<"Bfs.begin:"<<endl;
            queue<int> Q;
            while (!Q.empty())
                Q.pop();
            memset(Depth,0,sizeof(Depth));
            Depth[s]=1;
            Q.push(s);
            do
            {
                int u=Q.front();
                //cout<<u<<endl;
                Q.pop();
                for (int i=Head[u];i!=-1;i=Next[i])
                {
                    if ((W[i]>0)&&(Depth[V[i]]==0))
                    {
                        Depth[V[i]]=Depth[u]+1;
                        Q.push(V[i]);
                    }
                }
            }
            while (!Q.empty());
            //cout<<"Bfs.end"<<endl;
            if (Depth[t]>0)
                return 1;
            return 0;
        }
    int Dinic()
        {
            int Ans=0;
            while (bfs())
            {
                while (int d=dfs(s,inf))
                    Ans+=d;
            }
            return Ans;
        }
        int main()
        {
            int num,i,bian,a,b,c,ss,tt;
            scanf("%d%d%d%d",&num,&bian,&ss,&tt);
            init(num,ss,tt);
            for(i=1;i<=bian;i++){
                scanf("%d%d%d",&a,&b,&c);
                Add_Edge(a,b,c);
            }
            
            printf("%d",Dinic());
        }
总代码 Luogu 3376
原文地址:https://www.cnblogs.com/Fish-/p/8253796.html