zoukankan      html  css  js  c++  java
  • 网络流 EdmonsKarp 算法讲解

    网络流EK算法
    数据结构:队列
    主要操作:广搜 记录路径 更新
    能解决的问题:最大流(最小割)
    复杂度:O(MV)v指最大容量,M指边数。
    新名词:
        1.增广路:从源点source到tink的一条简单路,如果路上的每条边(u,v)的可改进量均大于0,则称这条路为一条增广路。
        增广路定理:网络达到最大流量当且仅当不存在增广路。
        增广路算法:从一个可行流开始不断的寻找可增广路,然后沿着它增广,直到它不存在。
        2.反向弧:如果有一条弧(u,v),那么再进行网络流算法时,要对它建立反向弧(v,u),反向弧的容量为0,与正向弧相反,正向弧减少容量时,反向弧增加容量。建立反向弧能更多的增广,使网络流算法正确。(无法给出证明)
        3.可行弧:在EK算法中指可从u到v增加流量(也就是容量不为0)。
        4.可行路:从源点source到tink的有可行弧构成的路径叫做可行路。    
    
    具体操作:
        1.建立网络(正向弧+反向弧)
        2.从源点出发,广搜一条最短可行路(即最先到达汇点tink的那条路),每次到达一个点用pre数组记录是由那条边过来的(为后面减小流量做准备)
        3.到达汇点tink时,按照pre数组记录的,从可行路中找一条容量最小的进行容量减少。即找到了一条割边。
        4.重复操作2.3,直到无法到达汇点,算法结束,即找到了最大流,算法结束。
    
    推荐水题:USACO 4.2.1 纯网络流算法,可用来试EK的正确性,但EK只能拿50分!
      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstdlib>
      4 #include<cstring>
      5 using namespace std;
      6 
      7 #define INF 1000000  
      8 
      9 struct    Edge
     10 {
     11     int x,y,flow,next,op;//flow表示当前边的容量  op表示正向弧所对应的反向弧在边表中的位置
     12 };
     13 
     14 Edge map[200];
     15 int que[20000];
     16 bool b[500];//用b数组记录是否入队,可以防止重复入队,因为有反向弧和环!!
     17 int source,tink,n,m,tot,ans,head,tail;
     18 int first[500];
     19 int pre[500];
     20 
     21 int fmin(int x ,int y)
     22 {
     23     if (x<y)    return x;
     24     else return y;
     25 }
     26 
     27 void Build(int x ,int y ,int c)
     28 {
     29     tot++;//正向弧
     30     map[tot].x=x;
     31     map[tot].y=y;
     32     map[tot].flow=c;
     33     map[tot].next=first[x];
     34     first[x]=tot;
     35     map[tot].op=tot+1;
     36     tot++;//反向弧
     37     map[tot].x=y;
     38     map[tot].y=x;
     39     map[tot].flow=0;//反向弧容量为0
     40     map[tot].next=first[x];
     41     first[x]=tot;
     42     map[tot].op=tot-1;
     43 }
     44 
     45 void init()
     46 {
     47     memset(first,0,sizeof(first));
     48     tot=0;     ans=0;
     49     scanf("%d%d",&m,&n);
     50     for (int i=1; i<=m; i++)
     51     {
     52         int x,y,c;
     53         scanf("%d%d%d",&x,&y,&c);
     54         Build(x,y,c);                
     55     }
     56     source=n+1;     tink=n+2;//手动建立源点和汇点,看题目要求!
     57     Build(source,1,INF);
     58     Build(n,tink,INF);
     59 }
     60 
     61 bool Bfs()
     62 {
     63     memset(b,false,sizeof(b));
     64     head=1;    tail=1;     que[1]=source;    b[source]=true;    pre[source]=-1;//没有可以到源点的路
     65     while (head<=tail)
     66     {
     67         int x=que[head];
     68         int t=first[x];        
     69         while (t>0)
     70         {
     71             int y=map[t].y;            
     72             if (map[t].flow>0    &&    b[y]==false)//找到一条可行弧
     73             {                
     74                 tail++;
     75                 que[tail]=y;
     76                 b[y]=true;
     77                 pre[y]=t;//路径记录
     78                 if (y==tink)    return true;//到达汇点,退出广搜
     79             }
     80             t=map[t].next;
     81         }
     82         head++;
     83         b[x]=false;
     84     }    
     85     return false;
     86 }
     87 
     88 void updata()
     89 {    
     90     int Min=INF;
     91     for (int p=pre[tink];p!=-1;p=pre[map[p].x])    
     92     {
     93         Min=fmin(Min , map[p].flow);//找可行路中的最小容量
     94     }
     95     for (int p=pre[tink];p!=-1;p=pre[map[p].x])//更新容量过程    
     96     {
     97         map[p].flow-=Min;
     98         map[map[p].op].flow+=Min;//反向弧增加容量
     99     }
    100     ans+=Min;    
    101 }
    102 
    103 void EK()
    104 {
    105     
    106     while (Bfs()==true)
    107     {
    108         updata();    
    109     }
    110     printf("%d\n",ans);    
    111 }
    112 
    113 int main()
    114 {
    115     freopen("ditch.in","r",stdin);
    116     freopen("ditch.out","w",stdout);
    117     init();
    118     EK();    
    119     return 0;    
    120     fclose(stdin); fclose(stdout);
    121 }
  • 相关阅读:
    Linux下的邮件发送
    Linux下用户和raid练习题
    Linux centos7.5操作系统的安装
    Linux chattr文件锁
    Linux系统下root密码丢失解决方案
    周总结2
    课堂作业1
    开课博客
    阅读3
    作业8
  • 原文地址:https://www.cnblogs.com/acSzz/p/2477742.html
Copyright © 2011-2022 走看看