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)。
注意:增广路的长度是递增的。
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;