网络流学习笔记
0.引入
1.EK算法:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #define rgi register int 6 #define il inline 7 #define ll long long 8 #define maxn 10010 9 #define maxm 100010<<1 10 //记得双向边要开两倍 11 #define inf 0x3f3f3f3f 12 13 using namespace std; 14 15 int n, m, s, t, cnt; 16 int vis[maxn], first[maxn]; 17 18 struct edge 19 { 20 int to, _next, wt; 21 } e[maxm]; 22 23 struct node 24 { 25 int to, id; 26 } pre[maxn];//记录前驱 27 28 il void Add_Edge(int u, int v, int w) 29 { 30 e[cnt].to = v; 31 e[cnt].wt = w; 32 e[cnt]._next = first[u]; 33 first[u] = cnt++; 34 }//加边 35 36 il int bfs(int s, int t) 37 { 38 memset(vis, 0, sizeof(vis)); 39 memset(pre, -1, sizeof(pre));//记得要初始化 40 queue <int> q; 41 pre[s].to = s; 42 vis[s] = 1; 43 q.push(s);//入队 44 while(!q.empty()) 45 { 46 int x = q.front();//取队首元素 47 q.pop(); 48 for(rgi i = first[x]; i != -1; i = e[i]._next) 49 { 50 int y = e[i].to; 51 if(!vis[y] && e[i].wt > 0)//若y未被访问过且这条路上还有剩余流量 52 { 53 pre[y].to = x; 54 pre[y].id = i;//记录前驱 55 vis[y] = 1;//表示已经访问过了 56 if(y == t) 57 return 1;//到了汇点 58 q.push(y);//入队 59 } 60 } 61 } 62 return 0;//若不能增广,则返回0 63 } 64 65 il int EK(int s, int t) 66 { 67 int res = 0; 68 while(bfs(s, t)) 69 { 70 int cur_min_flow = inf;//初始化最小残余流量为inf 71 for(rgi i = t; i != s; i = pre[i].to) 72 cur_min_flow = min(cur_min_flow, e[pre[i].id].wt);//沿着前驱回溯并更新最小残余流量 73 for(rgi i = t; i != s; i = pre[i].to) 74 { 75 e[pre[i].id].wt -= cur_min_flow;//把这条增广路上的所有流量都减去最小残余流量 76 e[pre[i].id ^ 1].wt += cur_min_flow;//反向边就要加上最小残余流量 77 } 78 res += cur_min_flow;//最大流加上这次增广所得的流量 79 } 80 return res; 81 } 82 83 int main() 84 { 85 memset(first, -1, sizeof(first)); 86 scanf("%d %d %d %d", &n, &m, &s, &t); 87 for(rgi i = 1; i <= m; ++i) 88 { 89 int u, v, w; 90 scanf("%d %d %d", &u, &v, &w); 91 Add_Edge(u, v, w); 92 Add_Edge(v, u, 0);//反向边 93 } 94 printf("%d", EK(s, t)); 95 return 0; 96 }
2.Dinic算法+当前弧优化:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <algorithm> 5 #define rgi register int 6 #define il inline 7 #define ll long long 8 #define maxn 210<<1 9 #define maxm 210<<1 10 #define inf 0x3f3f3f3f 11 12 using namespace std; 13 14 int n, m, s, t, cnt; 15 int first[maxn], dep[maxn], curEdge[maxn]; 16 17 struct edge 18 { 19 int to, _next, wt; 20 } e[maxm]; 21 22 il void Add_Edge(int u, int v, int w) 23 { 24 e[cnt].to = v; 25 e[cnt].wt = w; 26 e[cnt]._next = first[u]; 27 first[u] = cnt++; 28 }//加边 29 30 il int bfs() 31 { 32 memset(dep, -1, sizeof(dep)); 33 dep[t] = 0;//从汇点开始,设置汇点的深度为0 34 queue <int> q; 35 q.push(t);//入队 36 while(!q.empty()) 37 { 38 int x = q.front();//取出队首 39 q.pop(); 40 for(rgi i = first[x]; i != -1; i = e[i]._next) 41 { 42 int y = e[i].to; 43 if(dep[y] == -1 && e[i ^ 1].wt > 0)//如果y未被染色到,且反向边还有流量 44 { 45 dep[y] = dep[x] + 1;//染色 46 q.push(y);//入队 47 } 48 } 49 } 50 return dep[s] != -1;//看是否能染到源点 51 }//分层 52 53 il int dfs(int u, int v, int flow) 54 { 55 if(u == t) 56 return flow; 57 int delta = flow; 58 for(rgi &i = curEdge[u]; i != -1; i = e[i]._next)//当前弧优化(亟待掌握) 59 { 60 int cur = e[i].to; 61 if(dep[u] == dep[cur] + 1 && e[i].wt) 62 { 63 int dfn = dfs(cur, v, min(delta, e[i].wt)); 64 e[i].wt -= dfn; 65 e[i ^ 1].wt += dfn; 66 delta -= dfn; 67 if(!delta) 68 break; 69 } 70 } 71 return flow - delta; 72 } 73 74 il int dinic() 75 { 76 int res = 0; 77 while(bfs()) 78 { 79 for(rgi i = 0; i < n; ++i) 80 curEdge[i] = first[i];//复制当前弧 81 res += dfs(s, t, inf);//更新最大流 82 } 83 return res; 84 } 85 86 int main() 87 { 88 scanf("%d %d %d %d", &n, &m, &s, &t); 89 memset(first, -1, sizeof(first)); 90 for(rgi i = 1; i <= m; ++i) 91 { 92 int u, v, w; 93 scanf("%d %d %d", &u, &v, &w); 94 Add_Edge(u, v, w); 95 Add_Edge(v, u, 0);//反向边 96 } 97 printf("%d", dinic()); 98 return 0; 99 }
posted on 2019-03-30 22:28 Clever_Jimmy 阅读(114) 评论(0) 编辑 收藏 举报