zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    xaml的margin和css的margin对比
    easyui datagrid连续删除问题
    面试常用的代码片段
    JS实现table表格在鼠标移动出现一行变色或者十字叉变色
    Ubuntu 18.04 LTS 64位Linux搭建Kubernetes 1.15.3并join子节点的完整过程
    Java定义队结构,实现入队、出队操作
    Java定义栈结构,实现入栈、出栈操作
    Java构造二叉树、树形结构先序遍历、中序遍历、后序遍历
    MySQL计算两个日期相差的天数、月数、年数
    Nginx(web服务器)与Tomcat(应用服务器)搭建集群
  • 原文地址:https://www.cnblogs.com/Fish-/p/8253796.html
Copyright © 2011-2022 走看看