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 }
  • 相关阅读:
    SCAU 9504 面试
    SCAU 9503 懒人选座位
    SCAU 8628 相亲
    SCAU 10691 ACM 光环
    SCAU 8626 原子量计数
    SCAU 10674 等差对
    HDU ACM 1048 The Hardest Problem Ever (水题)
    SCAU 9502 ARDF
    SCAU 10686 DeathGod不知道的事情
    SCAU 8629 热身游戏(高精度)
  • 原文地址:https://www.cnblogs.com/acSzz/p/2477742.html
Copyright © 2011-2022 走看看