Clever_Jimmy

导航

网络流学习笔记

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编辑  收藏  举报