• ISAP学习笔记


    学完了ISAP,感觉心情舒畅,毕竟ISAP比Dinic好一点。

    说到底ISAP其实是Dinic(不熟悉Dinic的人去我的博客找猴子课堂----最大流与最小割(看看思想),已经置顶)优化版,熟悉的人知道Dinic是通过不断分层来做的,但是,我们如果用打标记(貂蝉的标记)的方法就会快一些!

    会快的原因就是因为他省了很多分层的时间,使得他比Dinic要快不少,首先,我们先初始化一遍(从t开始搜,建个分层图(不是说不用宽搜了吗)),虽然过程中不用多次分层,但初始化分层,使得代码要干的事情少了不少(因为让代码通过自身调整标记要O(n^2)时间,但如果用宽搜初始化分层就让时间缩短为O(n),也是十分不错的呢!)

    然后每次按分层规矩(注意,这里以结尾为原点建分层图,是由高的层流向比他低一层的层)找一条路径(没错,你没听错,就是单路增广!),从起点出发:

    这张

    流完后,然后回到起点,找另外一条流完,就结束了?

    1
    2

    比如这张:

    呵呵

    下面一条可行路径就因为———(儿童不宜)的关系流不过去了(分层有时会导致两个相邻点层数相同)。。。

    所以,ISAP的精华!出来吧!

    呵呵

    询问?询问什么?就是找与他相连的点(边要有流量)中层数最小的,之后,它就可以变身成比这个编号大一层的点(没有就为n+1),继续为流量做贡献!(在一个点找不到下一个点时,就调整这个点的标记)

    呵呵

    改完之后:

    呵呵

    就这样解决了呢!(只需要在s的层数大于点数就可以退出了)

    呵呵

    呵呵

    但是,我们仔细思考一下,标记其实是具有连续性的,因为你这个标记改了,你附近的标记也会随你+1或者走其他和你之前编号一样的点,所以每次+1就足够了,时间没多大差别,代码更短,何乐而不为?

    断层优化:

    当一个编号没有一个点,便可以结束,为什么?

    我们可以知道,假设断层编号为x,那么起点大于x,容易知道,我们无法到达编号小于x的点,于是便可以结束。

    然后,上!代码。。。

    #include<cstdio>
    #include<cstring>
    using  namespace  std;
    struct  node
    {
        int  y,c,next;
    }a[210000];int  len=1,last[21000],st,ed;
    int  num[21000],cur[21000],qian[21000],h[21000],n,m;
    int  mymin(int  x,int  y){return  x<y?x:y;}
    void  ins(int  x,int  y,int  c)
    {
        len++;
        a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;
        len++;
        a[len].y=x;a[len].c=0;a[len].next=last[y];last[y]=len;
    }
    int  list[21000],head,tail;
    void  bfs()
    {
        head=1;tail=2;list[head]=ed;h[ed]=1;num[1]++;
        while(head!=tail)
        {
            int  x=list[head];
            for(int  k=last[x];k;k=a[k].next)
            {
                if(h[a[k].y]==0  &&  a[k^1].c>0)
                {
                    num[h[a[k].y]=h[x]+1]++;
                    list[tail++]=a[k].y;
                }
            }
            head++;
        }
        if(h[st]==0)h[st]=n+1;
    }
    int  add()
    {
        int  now=ed,ans=999999999;
        while(now!=st)
        {
            ans=mymin(ans,a[qian[now]].c);
            now=a[qian[now]^1].y;
        }
        now=ed;
        while(now!=st)
        {
            a[qian[now]].c-=ans;a[qian[now]^1].c+=ans;
            now=a[qian[now]^1].y;
        }
        return  ans;
    }
    int  findflow()
    {
        int  ans=0,now=st;
        bfs();
        while(h[st]<=n)
        {
            bool  bk=true;
            while(bk==true)
            {
                bk=false;
                for(int  k=cur[now];k;k=a[k].next)
                {
                    if(a[k].c>0  &&  h[a[k].y]+1==h[now])
                    {
                        bk=true;
                        cur[now]=k;
                        now=a[k].y;
                        qian[now]=k;
                        break;
                    }
                }
                if(now==ed)
                {
                    ans+=add();now=st;
                }
            }
            if((--num[h[now]])==0)break;
            num[++h[now]]++;cur[now]=last[now];
            if(now!=st)now=a[qian[now]^1].y;
        }
        return  ans;
    }
    int  main()
    {
        scanf("%d%d%d%d",&n,&m,&st,&ed);
        for(int  i=1;i<=m;i++)
        {
            int  x,y,c;scanf("%d%d%d",&x,&y,&c);
            ins(x,y,c);
        }
        for(int  i=1;i<=n;i++)cur[i]=last[i];
        printf("%d
    ",findflow());
        return  0;
    }
    

    为什么会快?

    其实它比Dinic少了很多没用的递归,让每次找路径都有作用,而且用标记省了bfs的时间,所以,只要不被恶意卡掉,ISAP整体上比Dinic要优秀!

    呵呵

    注:上面的图片侵权抱歉!

  • 相关阅读:
    [lab]csappattack
    [lab]csappbomb
    springboot 与 springcloud 的版本选型
    猜你喜欢推荐系统算法(笔记)
    java idea 自动生成单元测试模板
    RetryableException: Connection refused (Connection refused) executing POST http://ctsmessagecenter/.....
    git 学习整理
    echarts知识点汇总
    状态模式(C#)
    Ant Design of Vue select加载远程数据完善方案
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/9694677.html
Copyright © 2020-2023  润新知