1 module dkh.graph.maxflow;
2 
3 import dkh.container.deque;
4 
5 /// maxflowの情報
6 struct MaxFlowInfo(C) {
7     C flow; /// 流量
8     bool[] dual; /// 最小カット(S側:false, T側:true)
9 }
10 
11 /**
12 MaxFlow(Dinic)
13 Params:
14     g = graph
15     s = source node
16     t = sink node
17     gap = maximum flow
18  */
19 MaxFlowInfo!(C) maxFlow(C, C EPS, T)(T g, size_t s, size_t t, C gap = C.max) {
20     assert(s != t);
21     import std.conv : to;
22     int[] level = new int[g.length];
23     int[] iter = new int[g.length];
24 
25     void bfs() {
26         level[] = -1; level[s] = 0;
27         auto que = Deque!int();
28         que.insertBack(s.to!int);
29         while (!que.empty) {
30             int v = que.front; que.removeFront;
31             foreach (e; g[v]) {
32                 if (e.cap <= EPS) continue;
33                 if (level[e.to] < 0) {
34                     level[e.to] = level[v] + 1;
35                     que.insertBack(e.to);
36                 }
37             }
38         }
39     }
40 
41     C dfs(int v, C f) {
42         import std.algorithm : min;
43         if (v == t) return f;
44         C res = 0;
45         auto edgeList = g[v][iter[v]..$];
46         foreach (ref e; edgeList) {
47             if (e.cap <= EPS) continue;
48             if (level[v] >= level[e.to]) continue;            
49             C d = dfs(e.to, min(f, e.cap));
50             e.cap -= d;
51             g[e.to][e.rev].cap += d;
52             res += d;
53             f -= d;
54             if (f == 0) break;
55             iter[v]++;
56         }
57         return res;
58     }
59 
60     C flow = 0;
61     while (gap - flow > EPS) {
62         bfs();
63         if (level[t] < 0) break;
64         iter[] = 0;
65         while (true) {
66             C f = dfs(s.to!int, gap - flow);
67             if (!f) break;
68             flow += f;
69         }
70     }
71 
72     import std.algorithm : map;
73     import std.range : array;
74     auto mfInfo = MaxFlowInfo!C();
75     mfInfo.flow = flow;
76     mfInfo.dual = level.map!"a == -1".array;
77     return mfInfo;
78 }
79 
80 ///
81 unittest {
82     import std.algorithm : equal;
83     import std.conv : to;
84     struct Edge {
85         int to, cap, rev;
86     }
87     void addEdge(Edge[][] g, int from, int to, int cap) {
88         g[from] ~= Edge(to, cap, g[to].length.to!int);
89         g[to] ~= Edge(from, 0, g[from].length.to!int-1);
90     }
91 
92     auto g = new Edge[][](4);
93 
94     addEdge(g, 0, 1, 3);
95     addEdge(g, 0, 2, 3);
96     addEdge(g, 1, 3, 2);
97     addEdge(g, 2, 3, 4);
98     auto res = maxFlow!(int, 0)(g, 0, 3);
99     assert(res.flow == 5);
100     //MinCut : S={0, 1}, T={2, 3}
101     assert(equal(res.dual, [false, false, true, true]));
102 }
103 
104 MaxFlowInfo!(C) maxFlowSlow(C, T)(T g, int s, int t, C gap = C.max) {
105     assert(s != t);
106     import std.algorithm : map;
107     import std.range : array;
108     import std.conv : to;
109     auto n = g.length;
110 
111     bool[] used = new bool[n];
112     bool dfs(int v) {
113         if (v == t) return true;
114         used[v] = true;
115         foreach (ref e; g[v]) {
116             if (used[e.to]) continue;
117             if (!e.cap) continue;
118             if (dfs(e.to)) {
119                 e.cap -= 1;
120                 g[e.to][e.rev].cap += 1;
121                 return true;
122             }
123         }
124         return false;
125     }
126     
127     C flow = 0;
128     while (flow < gap) {
129         used[] = false;
130         if (!dfs(s)) break;
131         flow++;
132     }
133     auto mfInfo = MaxFlowInfo!C();
134     mfInfo.flow = flow;
135     mfInfo.dual = used.map!"!a".array;
136     return mfInfo;
137 }
138 
139 unittest {
140     import std.algorithm, std.conv, std.stdio, std.range;
141     import std.random;
142     import std.typecons;
143 
144     struct E {
145         int to, cap, rev;
146     }
147     void addEdge(E[][] g, int from, int to, int cap) {
148         g[from] ~= E(to, cap, g[to].length.to!int);
149         g[to] ~= E(from, 0, g[from].length.to!int-1);
150     }
151 
152     void f(alias MF)() {
153         int n = uniform(2, 20);
154         int m = uniform(0, 200);
155         int s, t;
156         while (true) {
157             s = uniform(0, n);
158             t = uniform(0, n);
159             if (s != t) break;
160         }
161         auto g = new E[][n];
162         E[][] elist = new E[][n];
163 
164         foreach (i; 0..m) {
165             int x, y;
166             while (true) {
167                 x = uniform(0, n);
168                 y = uniform(0, n);
169                 if (x == y) continue;
170                 break;
171             }
172             int c = uniform(0, 100);
173             addEdge(g, x, y, c);
174             elist[x] ~= E(y, c, -1);
175         }
176 
177         auto res = MF(g, s, t);
178         assert(res.dual[s] == false);
179         assert(res.dual[t] == true);
180         int sm = 0;
181         foreach (i, v; elist) {
182             foreach (e; v) {
183                 if (res.dual[i] == false && res.dual[e.to] == true) {
184                     sm += e.cap;
185                 }
186             }
187         }
188         assert(res.flow == sm);
189     }
190 
191     import dkh.stopwatch;
192     auto ti = benchmark!(
193         f!(maxFlow!(int, 0, E[][])),
194         f!(maxFlowSlow!(int, E[][])),
195         )(1000);
196     writeln("MaxFlow Random1000: ", ti[].map!(a => a.toMsecs()));
197 }
198 
199 unittest {
200     import std.algorithm, std.conv, std.stdio, std.range, std.math;
201     import std.random;
202     import std.typecons;
203 
204     struct E {
205         int to;
206         double cap;
207         int rev;
208     }
209     void addEdge(E[][] g, int from, int to, double cap) {
210         g[from] ~= E(to, cap, g[to].length.to!int);
211         g[to] ~= E(from, 0.0, g[from].length.to!int-1);
212     }
213     immutable double EPS = 1e-9;
214 
215     void f() {
216         int n = uniform(2, 20);
217         int m = uniform(0, 200);
218         int s = 0, t = 1;
219         auto g = new E[][n];
220         E[][] elist = new E[][n];
221 
222         foreach (i; 1..m) {
223             int x, y;
224             while (true) {
225                 x = uniform(0, n);
226                 y = uniform(0, n);
227                 if (x == y) continue;
228                 break;
229             }
230             double c = uniform(0.0, 100.0);
231             addEdge(g, x, y, c);
232             elist[x] ~= E(y, c, -1);
233         }
234 
235         auto res = maxFlow!(double, EPS)(g, 0, 1);
236         assert(res.dual[0] == false);
237         assert(res.dual[1] == true);
238         double sm = 0;
239         foreach (i, v; elist) {
240             foreach (e; v) {
241                 if (res.dual[i] == false && res.dual[e.to] == true) {
242                     sm += e.cap;
243                 }
244             }
245         }
246         assert(abs(res.flow - sm) < EPS);
247     }
248     import dkh.stopwatch;
249     auto ti = benchmark!(f)(5000);
250     writeln("MaxFlow Double Random5000: ", ti[0].toMsecs());
251 }