dinic算法

dinic算法是网络流最大流的优化算法之一,每一步对原图进行分层,然后用DFS求增广路。时间复杂度是O(n^2*m)(n是点数,m是边数)

层次图:把原图中的点按照到源的距离分“层”,只保留不同层之间的边的图。

算法流程:

1、根据残量网络计算层次图。

2、在层次图中使用DFS进行增广直到不存在增广路。

3、重复以上步骤直到无法增广。

时间复杂度:

因为在Dinic的执行过程中,每次重新分层,汇点所在的层次是严格递增的,而n个点的层次图最多有n层,所以最多重新分层n次。在同一个层次图中,因为每条增广路都有一个瓶颈,而两次增广的瓶颈不可能相同,所以增广路最多m条。搜索每一条增广路时,前进和回溯都最多n次,所以这两者造成的时间复杂度是O(nm);而沿着同一条边(i,j)不可能枚举两次,因为第一次枚举时要么这条边的容量已经用尽,要么点j到汇不存在通路从而可将其从这一层次图中删除。综上所述,Dinic算法时间复杂度的理论上界是O(n^2*m)。

注意:增广路的长度是递增的。

伪代码,摘自http://www.cnblogs.com/zen_chou/archive/0001/01/01/1525841.html

View Code
 1   初始化,计算剩余图;
 2   while(BFS())    //BFS过程的作用:1,计算层次图;2,当汇点不再层次图内时返回0
 3   {
 4      path.clear();
 5      源点入栈path;   //栈path保存层次图内从原点到终点的可行路径
 6      while(源点的出度不为0)
 7      {
 8         u<-path.top;
 9         if (u!=汇点)        //在层次图内寻找一条从起点到终点的路径
10         {
11           if (u出度大于0)
12             将层次图内与u相连的点v入栈;
13           else
14           {
15             u出栈;      //从path中删除
16             u的level=正无穷;   //从层次图中删除
17           }
18         }
19         else           //对路径增广
20         {
21           在剩余图中沿P增广;
22           令path.top为从起点可到达的最后一个顶点;
23         }
24      }
25   }

dinic代码,演示例子是算法导论P405图。

 

View Code
  1 View Code 
  2   1 #include <iostream>
  3   2 #include <stdio.h>
  4   3 #include <memory.h>
  5   4 #include <list>
  6   5 using namespace std;
  7   6 const int maxnum=21;
  8   7 const int maxdata=(1<<30);
  9   8 int f[maxnum][maxnum];
 10   9 int level[maxnum];
 11  10 bool use[maxnum];
 12  11 int p,e;
 13  12 
 14  13 void Init()
 15  14 {
 16  15     memset(f,0,sizeof(f));
 17  16     scanf("%d%d",&p,&e);
 18  17     int i;
 19  18     int u,v,w;
 20  19     for(i=0;i<e;i++)
 21  20     {
 22  21         scanf("%d%d%d",&u,&v,&w);
 23  22         f[u][v]+=w;
 24  23     }
 25  24 }
 26  25 
 27  26 bool bfs() //Construct the level graph
 28  27 {
 29  28     int i;
 30  29     for(i=1;i<=p;i++)  //start=1,end=p
 31  30     {
 32  31         level[i]=maxdata;
 33  32         use[i]=false;
 34  33     }
 35  34 
 36  35     list<int> l;
 37  36     l.clear();
 38  37     level[1]=0;
 39  38     use[1]=true;
 40  39     l.push_back(1);
 41  40     int t;
 42  41     bool flag=false;
 43  42     while(!l.empty())
 44  43     {
 45  44         t=l.front();
 46  45         l.pop_front();
 47  46         if(t==p)   //因为要求整个图中的层次图,所以最好不要break
 48  47             flag=true;
 49  48         for(i=1;i<=p;i++)
 50  49         {
 51  50             if(f[t][i]!=0 && !use[i])
 52  51             {
 53  52                 level[i]=level[t]+1;
 54  53                 use[i]=true;
 55  54                 l.push_back(i);
 56  55             }
 57  56         }
 58  57     }
 59  58     return flag;
 60  59 }
 61  60 
 62  61 int Outdegree(int u)//compute the out degree of a node in level graph
 63  62 {
 64  63     int i;
 65  64     for(i=1;i<=p;i++)
 66  65         if(f[u][i]!=0 && level[i]==level[u]+1)
 67  66             return i;
 68  67     return 0;
 69  68 }
 70  69 
 71  70 int Dinic()
 72  71 {
 73  72     int sum=0,cf,last;
 74  73     int start=1;
 75  74     int u,v;
 76  75     list<int> s;
 77  76     list<int>::iterator it;
 78  77     while(bfs())
 79  78     {
 80  79         //cout<<"bfs"<<endl;
 81  80         s.clear();
 82  81         s.push_back(start);   //s=1;
 83  82         while(Outdegree(start)>0)
 84  83         {
 85  84             u=s.back();//search the path from s to t in level gragh
 86  85             if(u!=p)
 87  86             {
 88  87                 if((v=Outdegree(u))>0)
 89  88                 {
 90  89                     s.push_back(v);
 91  90                 }
 92  91                 else
 93  92                 {
 94  93                     s.pop_back();
 95  94                     level[u]=maxdata;
 96  95                 }
 97  96             }
 98  97             else //update the residual graph along path
 99  98             {
100  99 
101 100                 cf=maxdata;
102 101                 for(it=s.begin();it!=s.end();it++)
103 102                 {
104 103                     u=*it;
105 104                     //if(u==p)    break;
106 105                     it++;
107 106                     if(it==s.end())
108 107                         break;
109 108                     v=*(it);
110 109                     it--;
111 110                     if(f[u][v]<cf)
112 111                         cf=f[u][v];
113 112                 }
114 113 
115 114                 sum+=cf;
116 115                 last=-1;
117 116                 for(it=s.begin();it!=s.end();it++)
118 117                 {
119 118                     u=*it;
120 119                     //if(u==p)    break;
121 120                     it++;
122 121                     if(it==s.end())
123 122                         break;
124 123                     v=*(it);
125 124                     it--;
126 125                     f[u][v]-=cf;
127 126                     f[v][u]+=cf;
128 127                     if(f[u][v]==0 && last==-1)
129 128                         last=u;//label the last vertex reachable from s
130 129                 }
131 130 
132 131                 while(s.back()!=last)
133 132                     s.pop_back();
134 133             }
135 134         }
136 135     }
137 136     return sum;
138 137 }
139 138 
140 139 int main()
141 140 {
142 141     Init();
143 142     printf("%d\n",Dinic());
144 143     return 0;
145 144 }
146 145 
147 146 
148 147 
149 148 /*
150 149 6 10
151 150 1 2 16
152 151 1 3 13
153 152 2 3 10
154 153 2 4 12
155 154 3 2 4
156 155 3 5 14
157 156 4 3 9
158 157 4 6 20
159 158 5 4 7
160 159 5 6 4
161 160 */
162 161 //for(it=s.begin();it!=s.end();it++)
163 162 //                    cout<<*it<<" ";
164 163 //                cout<<endl;

 

 

转载于:https://www.cnblogs.com/pushing-my-way/archive/2012/08/13/2636895.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值