1、定义
可行流
设f(u,v)表示边(u,v)的当前容量上限
设c(u,v)表示边(u,v)的最大容量上限
如果网络流图中的流量满足
- 源点S:流出量=流量总量
- 汇点T:流入量=流量总量
- 任意边(u,v):0<=f(u,v)<=c(u,v)
则称该流为一个可行流
增广
增加一条路径的流量,即减少这条路径的当前流量上限,即f(u,v)的值
增广是我们求解最大流的基础
最大流
在所有可行流中流量最大的流
2、模板
EK算法
maxFlowEK返回值即为网络中最大值,cap数组中原边的逆边即为每个边的流量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| int cap[maxMN][maxMN]; int pre[maxMN], flow[maxMN]; void maxFlowInit(){ memset(cap,0,sizeof(cap)); memset(flow,0,sizeof(flow)); } int maxFlowEKBFS(int from, int to){ queue<int> q; int i; memset(pre,-1,sizeof(pre)); pre[from] = 0; flow[from] = maxCap; q.push(from); while(!q.empty()) { int id = q.front(); q.pop(); if(id == to) break; for(i = 0 ; i <= superTo; i++){ if(i != from && cap[id][i]>0 && pre[i] == -1){ pre[i] = id; flow[i] = min(cap[id][i], flow[id]); q.push(i); } } } if(pre[to] == -1) return -1; else return flow[to]; } int maxFlowEK(int from, int to){ int ins = 0, resMaxFlow = 0; while((ins = maxFlowEKBFS(from, to)) != -1){ int tmp = to; while(tmp != from){ int last = pre[tmp]; cap[last][tmp] -= ins; cap[tmp][last] += ins; tmp = last; } resMaxFlow += ins; } return resMaxFlow; }
|
Dinic算法
当前弧优化版本。
maxFlowDinic返回值即为网络中最大值,edge数组中原边的逆边即为每个边的流量,每个边的下一个边即为逆边。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| struct Node{ int from, to, cap; }edge[maxMN * maxMN << 1]; int cur[maxMN * maxMN << 1], dep[maxMN * maxMN << 1], que[maxMN * maxMN << 1], cnt = 0; void maxFlowDinicInit(){ cnt = 0; memset(pre, -1, sizeof(pre)); } void addEdge(int from, int to, int cap){ edge[cnt].from = to; edge[cnt].to = pre[from]; edge[cnt].cap = cap; pre[from] = cnt++; edge[cnt].from = from; edge[cnt].to = pre[to]; edge[cnt].cap = 0; pre[to] = cnt++; } bool maxFlowDinicBFS(){ memset(dep, 0, sizeof(dep)); dep[superFrom] = 1; int le = 0, ri = 1; que[++le] = superFrom; while(le <= ri){ int now = que[le++]; for(int iq = pre[now]; iq != -1; iq = edge[iq].to) if(!dep[edge[iq].from] && edge[iq].cap){ dep[edge[iq].from] = dep[now] + 1; que[++ri] = edge[iq].from; if(edge[iq].from == superTo) return true; } } return dep[superTo]; } int maxFlowDinicDFS(int now, int flow){ if(now == superTo) return flow; int sumFlow = 0; for(int iq = pre[now]; iq != -1; iq = edge[iq].to){ if(dep[edge[iq].from] == dep[now] + 1 && edge[iq].cap){ int ins = maxFlowDinicDFS(edge[iq].from, min(flow, edge[iq].cap)); edge[iq].cap -= ins; edge[iq ^ 1].cap += ins; sumFlow += ins; flow -= ins; if(flow <= 0) break; } } return sumFlow; } int maxFlowDinic(){ int maxFlow = 0; while(maxFlowDinicBFS()){ memcpy(cur, pre, sizeof(pre)); maxFlow += maxFlowDinicDFS(superFrom, 2 * maxCap); } return maxFlow; }
|
3、总结
可以解决很多网络上流量分配,聚类等问题。问题的关键在于如何建图,对于多源点多汇点的图可以添加超源和超汇进行解决。EK算法时间复杂度$O(nm^2)$,Dinic算法的时间复杂度$O(mn^2)$,可以根据图的稀疏程度选取对应算法。