1 module dkh.graph.mincostflow; 2 3 import dkh.container.deque; 4 5 /// 最小費用流の情報 6 struct MinCostFlowInfo(C, D, D EPS, T) { 7 T g; 8 int s, t; 9 C nc, capFlow; /// 今の最短路の容量, 今流した量 10 D nd, flow; /// 今の最短路の長さ, 今流したコスト 11 D[] dual; /// 双対問題の答え(=ポテンシャル) 12 private int[] pv, pe; 13 this(T g, int s, int t) { 14 this.g = g; 15 this.s = s; 16 this.t = t; 17 flow = D(0); 18 dual = new D[g.length]; dual[] = D(0); 19 pv = new int[g.length]; 20 pe = new int[g.length]; 21 } 22 } 23 24 /// 最小費用流 25 MinCostFlowInfo!(C, D, EPS, T) minCostFlow(C, D, D EPS, T)(T g, int s, int t, bool neg = false) { 26 assert(s != t); 27 auto mcfInfo = MinCostFlowInfo!(C, D, EPS, T)(g, s, t); 28 mcfInfo.dualRef(neg); 29 return mcfInfo; 30 } 31 32 /// 33 unittest { 34 import std.conv : to; 35 struct Edge { 36 int to, cap, dist, rev; 37 } 38 39 void addEdge(Edge[][] g, int from, int to, int cap, int dist) { 40 g[from] ~= Edge(to, cap, dist, g[to].length.to!int); 41 g[to] ~= Edge(from, 0, -dist, g[from].length.to!int-1); 42 } 43 44 auto g = new Edge[][](4); 45 46 addEdge(g, 0, 1, 10, 3); 47 addEdge(g, 0, 2, 12, 3); 48 addEdge(g, 1, 3, 3, 2); 49 addEdge(g, 2, 3, 20, 4); 50 51 auto mcfInfo = minCostFlow!(int, int, 0)(g, 0, 3, false); 52 //最初は 0->1->3で容量3, 距離5を流せる 53 assert(mcfInfo.nc == 3 && mcfInfo.nd == 5); 54 55 //最短経路が変わらない間(=容量3)流す 56 mcfInfo.singleFlow(10^^9); 57 58 assert(mcfInfo.capFlow == 3 && mcfInfo.flow == 15); 59 60 //次は 0->2->3で容量12, 距離7を流せる 61 assert(mcfInfo.nc == 12 && mcfInfo.nd == 7); 62 63 //最短経路が変わらない間(=容量12)流す 64 mcfInfo.singleFlow(10^^9); 65 66 assert(mcfInfo.capFlow == 3 + 12); 67 assert(mcfInfo.flow == 15 + 12*7); 68 } 69 70 ///min(nc, c)流す 71 C singleFlow(C, D, alias EPS, T)(ref MinCostFlowInfo!(C, D, EPS, T) mcfInfo, C c) { 72 import std.algorithm; 73 with (mcfInfo) { 74 if (nd == D.max) return nc; 75 c = min(c, nc); 76 for (int v = t; v != s; v = pv[v]) { 77 g[pv[v]][pe[v]].cap -= c; 78 g[v][g[pv[v]][pe[v]].rev].cap += c; 79 } 80 capFlow += c; 81 flow += c * nd; 82 nc -= c; 83 if (!nc) dualRef(mcfInfo, false); 84 } 85 return c; 86 } 87 88 ///流量がcになるまで流せるだけ流し続ける 89 void manyFlow(C, D, alias EPS, T)(ref MinCostFlowInfo!(C, D, EPS, T) mcfInfo, C c) { 90 with (mcfInfo) { 91 while (c) { 92 C f = singleFlow(mcfInfo, c); 93 if (!f) break; 94 c -= f; 95 } 96 } 97 } 98 99 import dkh.container.stackpayload; 100 import dkh.container.radixheap; 101 102 void dualRef(bool neg, C, D, alias EPS, T)(ref MinCostFlowInfo!(C, D, EPS, T) mcfInfo) { 103 import std.conv : to; 104 import std.traits : isIntegral; 105 import std.typecons; 106 import std.container; 107 import std.algorithm; 108 alias P = Tuple!(int, "to", D, "dist"); 109 110 with(mcfInfo) { 111 int n = g.length.to!int; 112 D[] dist = new D[n]; dist[] = D.max; 113 pv[] = -1; pe[] = -1; 114 StackPayload!int refV; 115 auto que = (){ 116 static if (!neg) { 117 static if (isIntegral!D) { 118 return RadixHeap!(P, "a.dist")(); 119 } else { 120 return heapify!"a.dist>b.dist"(make!(Array!P)); 121 } 122 } else { 123 return Deque!P(); 124 } 125 }(); 126 void insert(P p) { 127 static if (!neg) { 128 que.insert(p); 129 } else { 130 que.insertBack(p); 131 } 132 } 133 P pop() { 134 P p; 135 static if (!neg) { 136 p = que.front(); 137 que.removeFront(); 138 } else { 139 p = que.back(); 140 que.removeBack(); 141 } 142 return p; 143 } 144 insert(P(s, D(0))); 145 dist[s] = D(0); 146 while (!que.empty) { 147 P p = pop(); 148 int v = p.to; 149 if (dist[v] < p.dist) continue; 150 if (!neg) { 151 if (v == t) break; 152 refV ~= v; 153 } 154 foreach (int i, e; g[v]) { 155 D ed = e.dist + dual[v] - dual[e.to]; 156 if (e.cap && dist[e.to] > dist[v] + ed + EPS) { 157 dist[e.to] = dist[v] + ed; 158 pv[e.to] = v; pe[e.to] = i; 159 insert(P(e.to, dist[e.to])); 160 } 161 } 162 } 163 if (dist[t] == D.max) { 164 nd = D.max; 165 nc = 0; 166 return; 167 } 168 static if (!neg) { 169 foreach (v; refV.data) { 170 if (dist[v] >= dist[t]) continue; 171 dual[v] += dist[v]-dist[t]; 172 } 173 } else { 174 for (int v = 0; v < n; v++) { 175 if (dist[v] == D.max) dual[v] = D.max; 176 else dual[v] += dist[v]; 177 } 178 } 179 180 nd = dual[t]-dual[s]; 181 nc = C.max; 182 for (int v = t; v != s; v = pv[v]) { 183 nc = min(nc, g[pv[v]][pe[v]].cap); 184 } 185 } 186 } 187 188 void dualRef(C, D, alias EPS, T)(ref MinCostFlowInfo!(C, D, EPS, T) mcfInfo, bool neg) { 189 if (neg == false) { 190 dualRef!false(mcfInfo); 191 } else { 192 dualRef!true(mcfInfo); 193 } 194 } 195 196 unittest { 197 import std.algorithm, std.conv, std.stdio, std.range; 198 import std.random; 199 import std.typecons; 200 201 struct E { 202 int to, cap, dist, rev; 203 } 204 void addEdge(E[][] g, int from, int to, int cap, int dist) { 205 g[from] ~= E(to, cap, dist, g[to].length.to!int); 206 g[to] ~= E(from, 0, -dist, g[from].length.to!int-1); 207 } 208 209 void f(bool neg)() { 210 int n = uniform(2, 20); 211 int m = uniform(0, 200); 212 int s, t; 213 while (true) { 214 s = uniform(0, n); 215 t = uniform(0, n); 216 if (s != t) break; 217 } 218 auto g = new E[][n]; 219 E[][] elist = new E[][n]; 220 221 foreach (i; 0..m) { 222 int x, y; 223 while (true) { 224 x = uniform(0, n); 225 y = uniform(0, n); 226 if (x == y) continue; 227 break; 228 } 229 int c = uniform(0, 100); 230 int d = uniform(0, 100); 231 addEdge(g, x, y, c, d); 232 elist[x] ~= E(y, c, d, -1); 233 } 234 235 auto res = minCostFlow!(int, int, 0)(g, s, t, neg); 236 res.manyFlow(10^^9); 237 int sm = (res.dual[t]-res.dual[s]) * res.capFlow; 238 foreach (i, v; elist) { 239 foreach (e; v) { 240 sm -= (max(0L, (long(res.dual[e.to]) - res.dual[i]) - e.dist) * e.cap).to!long; 241 } 242 } 243 assert(res.flow == sm); 244 } 245 import dkh.stopwatch; 246 auto ti = benchmark!(f!false, f!true)(500); 247 writeln("MinCostFlow int Random500, Neg500: ", ti[].map!(a => a.toMsecs)); 248 } 249 250 unittest { 251 import std.algorithm, std.conv, std.stdio, std.range; 252 import std.random; 253 import std.typecons; 254 255 struct E { 256 int to, cap; 257 double dist; 258 int rev; 259 } 260 void addEdge(E[][] g, int from, int to, int cap, double dist) { 261 g[from] ~= E(to, cap, dist, g[to].length.to!int); 262 g[to] ~= E(from, 0, -dist, g[from].length.to!int-1); 263 } 264 265 void f(bool neg)() { 266 int n = uniform(2, 20); 267 int m = uniform(0, 200); 268 int s, t; 269 while (true) { 270 s = uniform(0, n); 271 t = uniform(0, n); 272 if (s != t) break; 273 } 274 auto g = new E[][n]; 275 E[][] elist = new E[][n]; 276 277 foreach (i; 0..m) { 278 int x, y; 279 while (true) { 280 x = uniform(0, n); 281 y = uniform(0, n); 282 if (x == y) continue; 283 break; 284 } 285 int c = uniform(0, 100); 286 double d = uniform(0.0, 100.0); 287 addEdge(g, x, y, c, d); 288 elist[x] ~= E(y, c, d, -1); 289 } 290 291 auto res = minCostFlow!(int, double, 1e-9)(g, s, t, neg); 292 res.manyFlow(10^^9); 293 double sm = (res.dual[t]-res.dual[s]) * res.capFlow; 294 foreach (i, v; elist) { 295 foreach (e; v) { 296 sm -= max(0.0, (res.dual[e.to] - res.dual[i]) - e.dist) * e.cap; 297 } 298 } 299 import std.math; 300 assert(abs(res.flow - sm) <= 1e-3); 301 } 302 import dkh.stopwatch; 303 auto ti = benchmark!(f!false, f!true)(500); 304 writeln("MinCostFlow double Random500, Neg500: ", ti[].map!(a => a.toMsecs)); 305 }