-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
138 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package graph | ||
|
||
typealias Capacity = Long | ||
typealias Cost = Long | ||
|
||
/** | ||
* Minimum-cost flow problemを扱うライブラリです。 | ||
* | ||
* [AC Library](https://atcoder.github.io/ac-library/production/document_ja/mincostflow.html) | ||
*/ | ||
class MinCostFlow(private val n: Int) { | ||
private val _edges = mutableListOf<Edge>() | ||
|
||
/** | ||
* [from]から[to]へ最大容量[cap], コスト[cost]の辺を追加する。何番目に追加された辺かを返す。 | ||
* | ||
* 0 <= [from], [to] < n | ||
* | ||
* 0 <= [cap], [cost] | ||
*/ | ||
public fun addEdge(from: Int, to: Int, cap: Capacity, cost: Cost): Int { | ||
assert(from in 0..<n) | ||
assert(to in 0..<n) | ||
assert(0 <= cap) | ||
assert(0 <= cost) | ||
val m = _edges.size | ||
_edges.add(Edge(from, to, cap, 0, cost)) | ||
return m | ||
} | ||
|
||
/** | ||
* [s]から[t]へ流せるだけ流し、その流量とコストを返す。 | ||
* @return (流量,コスト)のPair | ||
*/ | ||
public fun flow(s: Int, t: Int): Pair<Capacity, Cost> = flow(s, t, Capacity.MAX_VALUE) | ||
|
||
/** | ||
* [s]から[t]へ流量[flowLimit]まで流せるだけ流し、その流量とコストを返す。 | ||
* @return (流量,コスト)のPair | ||
*/ | ||
public fun flow(s: Int, t: Int, flowLimit: Capacity): Pair<Capacity, Cost> = slope(s, t, flowLimit).last() | ||
|
||
/** | ||
* 返り値に流量とコストの関係の折れ線が入る。全てのxについて、流量xのときの最小コストをg(x)とすると、(x,g(x))は返り値を折れ線として見たものに含まれる。 | ||
* * 返り値の最初の要素は(0,0) | ||
* * 返り値の.first、.secondは共に狭義単調増加 | ||
* * 3点が同一線上にあることはない | ||
* * 返り値の最後の要素は最大流量xとして(x,g(x)) | ||
*/ | ||
public fun slope(s: Int, t: Int): List<Pair<Capacity, Cost>> = slope(s, t, Capacity.MAX_VALUE) | ||
|
||
/** | ||
* 返り値に流量とコストの関係の折れ線が入る。全てのxについて、流量xのときの最小コストをg(x)とすると、(x,g(x))は返り値を折れ線として見たものに含まれる。 | ||
* * 返り値の最初の要素は(0,0) | ||
* * 返り値の.first、.secondは共に狭義単調増加 | ||
* * 3点が同一線上にあることはない | ||
* * 返り値の最後の要素はy = min(x, [flowLimit])として(y,g(y)) | ||
*/ | ||
public fun slope(s: Int, t: Int, flowLimit: Capacity): List<Pair<Capacity, Cost>> { | ||
assert(s in 0..<n) | ||
assert(t in 0..<n) | ||
assert(s != t) | ||
val m = _edges.size | ||
val edgeIdx = IntArray(m) { 0 } | ||
|
||
val degree = IntArray(n) { 0 } | ||
val redgeIdx = IntArray(m) { 0 } | ||
val elist = ArrayList<Pair<Int, InternalEdge>>(2 * m) | ||
for (i in _edges.indices) { | ||
val e = _edges[i] | ||
edgeIdx[i] = degree[e.from]++ | ||
redgeIdx[i] = degree[e.to]++ | ||
elist.add(e.from to InternalEdge(e.to, -1, e.cap - e.flow, e.cost)) | ||
elist.add(e.to to InternalEdge(e.from, -1, e.flow, -e.cost)) | ||
} | ||
val g = CSR(n, elist) | ||
for (i in _edges.indices) { | ||
val e = _edges[i] | ||
edgeIdx[i] += g.start[e.from] | ||
edgeIdx[i] += g.start[e.to] | ||
g.elist[edgeIdx[i]].rev = redgeIdx[i] | ||
g.elist[redgeIdx[i]].rev = edgeIdx[i] | ||
} | ||
|
||
val result = slope(g, s, t, flowLimit) | ||
|
||
for (i in _edges.indices) { | ||
val e = g.elist[edgeIdx[i]] | ||
_edges[i].flow = _edges[i].cap - e.cap | ||
} | ||
|
||
return result | ||
} | ||
|
||
private fun slope(g: CSR, s: Int, t: Int, flowLimit: Capacity): List<Pair<Capacity, Cost>> { | ||
val dualDist = Array<MutablePairCostCost>(n) { MutablePairCostCost(-1, -1) } | ||
val prevE = IntArray(n) { 0 } | ||
val vis = BooleanArray(n) { false } | ||
|
||
data class Q(val key: Cost, val to: Int) { | ||
operator fun compareTo(r: Q) = -key.compareTo(r.key) | ||
} | ||
|
||
val queMin = ArrayDeque<Int>() | ||
val que = ArrayDeque<Q>() | ||
|
||
fun dualRef() { | ||
for (i in 0..<n) { | ||
dualDist[i].second = Cost.MAX_VALUE | ||
|
||
|
||
|
||
|
||
} | ||
} | ||
} | ||
|
||
data class Edge(val from: Int, val to: Int, val cap: Capacity, var flow: Capacity, val cost: Cost) | ||
data class InternalEdge(val to: Int, var rev: Int, val cap: Capacity, val cost: Cost) | ||
data class MutablePairCostCost(var first: Cost, var second: Cost) | ||
class CSR(val n: Int, private val edges: List<Pair<Int, InternalEdge>>) { | ||
val start = IntArray(n + 1) { 0 } | ||
val elist = Array(edges.size) { InternalEdge(-1, -1, -1, -1) } | ||
|
||
init { | ||
for (e in edges) { | ||
start[e.first + 1]++ | ||
} | ||
for (i in 1..n) { | ||
start[i] += start[i - 1] | ||
} | ||
val counter = start.clone() | ||
for (e in edges) { | ||
elist[counter[e.first]++] = e.second | ||
} | ||
} | ||
} | ||
} |