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;