zoukankan      html  css  js  c++  java
  • 最大流的非递归Dinic算法

    Dinic是在Edmond_Karp上的优化,就是传说中的分层;分层听起来难理解,其实就是分级即给节点具有一定规则的标记,看一下实现就懂了!

    算法的实现步骤:

    1.分层:利用BFS搜索方式给每个节点给予标记level[i];

    2.判断分层是否成功即汇点是否被分到级别level[sink]!=0;

    3.在分层的基础上即level[i]上寻找所有的增广路、累计流量,回到步骤1;


    求最大流的非递归Dinic算法code:

    View Code
    //--------Dinic的非递归正向实现---------
    #define NOT(x) (x&1?x+1:x-1)

    struct Edge
    {
    int u;
    int value;
    int next;
    }edge[MAXM
    *2];
    int level[MAXN],queue[MAXN],node[MAXN],variednode[MAXN];//level给每一个节点分级,即分层;queue分层时当队列用,找增广路时
    int front,rear;//当栈用;node[i]为结点i的指针;variednode可变的结点指针(原本是node的复制,但是他不断变化);front,rear
    int index;//即队列的首尾;top即栈顶;index即作为edge的下标;
    int top;

    void Build_Graph(int m)//建图即建立网络
    {
    int v,u,value;
    index
    =0; memset(node,-1,sizeof(node));
    for(int i=0;i<m;i++)
    {
    scanf(
    "%d %d %d",&v,&u,&value);
    ++index; //这里用数组模拟指针,模拟链表结构
    edge[index].u=u; //重在自己慢慢体会,讲不出来效果的……
    edge[index].value=value;
    edge[index].next
    =node[v];
    node[v]
    =index;/////建立原网络

    ++index;
    edge[index].u
    =v;
    edge[index].value
    =0;
    edge[index].next
    =node[u];
    node[u]
    =index;/////建立反网络
    }
    }

    int Dinic(int source,int sink,int n)
    {
    int maxflow=0;
    int v,u,value;
    while(true)
    {
    memset(level,
    0,sizeof(level));
    front
    =rear=0; level[source]=1;
    queue[
    0]=source;
    while(front<=rear)/////传说中的分层
    {
    v
    =queue[front++];//注意这里的queue当队列用储存的是结点
    for(int i=node[v];i!=-1;i=edge[i].next)
    {
    u
    =edge[i].u; value=edge[i].value;
    if(value && level[u]==0)
    {
    level[u]
    =level[v]+1;
    queue[
    ++rear]=u;
    if(u==sink) break;
    }
    }
    if(u==sink) break;
    }

    if(level[sink]==0) break;//这个就是判断是否存在增广路,没有就结束了

    for(int i=1;i<=n;i++) variednode[i]=node[i];//看variednode——node的复制,以后就不断变化。这就是优化,记录下次开始访问的边。
    edge[0].u=source; top=0; queue[++top]=0;//这里的所做是为了“凑”下边的循环,这里的queue做栈用储存边的下标
    while(top)//////求该分层下的最短增广路
    {
    int i; v=edge[queue[top]].u;
    for(i=variednode[v];i!=-1;i=edge[i].next)
    {
    u
    =edge[i].u; value=edge[i].value;
    if(value && level[u]==level[v]+1)
    {
    queue[
    ++top]=i;
    variednode[v]
    =edge[i].next;
    break;
    }
    }
    if(i==-1) { variednode[v]=-1;top--;continue; }//若该点四周不存在最短增广路,则直接variednode[v]=-1;以防下次做
    //多余的查找。top--退一条边,再找

    if(u==sink)//找到一条边就判断一下该点是不是sink,不是继续向下找
    {
    int min=0x7fffffff,flag;
    for(i=2;i<=top;i++)
    if(min>edge[i].value)
    min
    =edge[i].value;//找到最大流量
    for(i=top;i>1;i--)
    {
    if(min==edge[queue[i]].value)
    flag
    =i;//更新该正向路径的各个流量,并标记出第一个流量变为0的边所在的栈位

    edge[queue[i]].value
    -=min;
    edge[NOT(queue[i])].value
    +=min;//看看怎么建图的吧 }
    top=flag-1;//更新top
    maxflow+=min;//更新maxflow
    }
    }
    }

    return maxflow;
    }

    这啥玩意缩进啊,草!气死我了,整了半天还这样……


    上边的代码,主要是第三步,我想了想感觉有可能会做太多的无用功——在level[i]的基础上找增广路,他是用DFS的方式查找增广路。他是从原点向汇点找,刚开始找到的边(符合条件的边)可能就不在增广路上,可是却要找到头才知道不是增广路,然后在一步步往回退,这岂不是做了大量的无用功?!感觉这样太盲目了~于是想了想:为什么不从汇点向原点找?从汇点向原点不是盲目的,刚开始找到的边(符合条件的边)一定在增广路上!这样就不会做像从原点到汇点找一样做许多无用功!!两段代码都差不多,具体细节看代码:
    View Code
    //------Dinic的非递归的反向实现------
    #define NOT(x) ( (x&1)?(x+1):(x-1) ) //取反边

    struct Edge
    {
       
    int u;
       
    int value;
       
    int next;
    }edge[MAXM];
    int node[MAXN],variednode[MAXN];
    int level[MAXN],queue[MAXN];
    int front,rear,top,index;

    void Build_Graph(int m)
    {
       
    int v,u,value;
        memset(node,
    -1,sizeof(node)); index=0;
       
    for(int i=0;i<m;i++)
        {
            scanf(
    "%d %d %d",&v,&u,&value);

            index
    ++;
            edge[i].u
    =u;
            edge[i].value
    =value;
            edge[i].next
    =node[v];
            node[v]
    =index;

            index
    ++;
            edge[i].u
    =v;
            edge[i].value
    =0;
            edge[i].next
    =node[u];
            node[u]
    =index;
        }   
    }

    int Dinic(int source,int sink,int n)
    {
       
    int max_flow=0;
       
    int i,v,u,value;
       
    while(true)
        {
            front
    =rear=0;
            queue[rear]
    =source;
            memset(level,
    0,sizeof(level)); level[source]=1;
           
    while(front>=rear)
            {
                v
    =queue[front++];
               
    for(i=node[v];i!=-1;i=edge[i].next)
                {
                    u
    =edge[i].u; value=edge[i].value;
                   
    if(value && level[u]==0)
                    {
                        level[u]
    =level[v]+1;
                        queue[
    ++rear]=u;
                       
    if(u==sink)    break;
                    }
                   
    if(u==sink)    break;
                }
            }
           
    if(level[sink]==0)    break;

           
    for(i=1;i<=n;i++)    variednode[i]=node[i];

            edge[
    0].u=sink; top=0; queue[++top]=0;
           
    while(top)
            {
                v
    =edge[queue[top]].u;
               
    for(i=variednode[v];i!=-1;i=edge[i].next)
                {
                    u
    =edge[i].u; value=edge[NOT(i)].value;
                   
    if(value && level[v]=level[u]+1)
                    {
                        variednode[v]
    =edge[i].next;
                        queue[
    ++top]=NOT(i);
                       
    break;
                    }
                }
               
    if(i==-1)
                {
                    variednode[v]
    =-1;
                    top
    --;    continue;
                }

               
    if(u==source)
                {
                   
    int min=0x7fffffff,flag;
                   
    for(i=2;i<=top;i++)
                    {
                       
    if(min>edge[queue[top]].value)
                            min
    =edge[queue[top]].value;
                    }
                   
    for(i=top;i>1;i--)
                    {
                       
    if(edge[queue[top]].value==min)
                            flag
    =i;
                        edge[queue[top]].value
    -=min;
                        edge[NOT(queue[top])].value
    +=min;
                    }
                    top
    =flag;
                    max_flow
    +=min;
                }
            }
        }
    }

    我感觉这样反着搜索比较好,可是是否会存在一些漏洞?不知道,至少我现在没发现;如果大虾你发现有什么不对,望能给我指正!十分感谢!!

  • 相关阅读:
    前端下载远程文件
    Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
    前端内存泄漏检查判断及处理
    在vue中使用import()来代替require.ensure()实现代码打包分离
    微信小程序将view动态填满全屏
    H5背景音乐自动播放(兼容微信IOS,进程后台切换自动停止播放,本文例子为Vue写法)
    JS获取移动端系统信息(操作系统、操作系统版本、横竖屏状态、设备类型、网络状态、生成浏览器指纹)
    JS判断图片是否加载完毕
    JS深度合并对象
    jsonp跨域请求
  • 原文地址:https://www.cnblogs.com/fornever/p/2182903.html
Copyright © 2011-2022 走看看