1
1
import type { ICircularQueue } from '@algorithm.ts/circular-queue'
2
2
import { createCircularQueue } from '@algorithm.ts/circular-queue'
3
- import type { Mcmf , McmfContext , McmfEdge } from './types'
3
+ import type { IMcmf , IMcmfContext , IMcmfEdge } from './types'
4
4
5
- export function createMcmf ( ) : Mcmf {
5
+ export interface IMcmfOptions {
6
+ /**
7
+ * A big number, representing the unreachable cost.
8
+ */
9
+ INF ?: number
10
+ }
11
+
12
+ export function createMcmf ( options : IMcmfOptions = { } ) : IMcmf {
6
13
let _source : number // The source point in a network flow
7
14
let _target : number // The sink in a network flow
8
15
let _n : number // The number of nodes in a network flow
9
16
let _mincost : number
10
17
let _maxflow : number
11
18
let _edgeTot : number
19
+ const _INF : number = options . INF ?? Number . MAX_VALUE / 2
12
20
const _inq : boolean [ ] = [ ] // Whether if the i-th node is in the queue.
13
21
const _dist : number [ ] = [ ] // The distance from the source node to the i-th node.
14
22
const _path : number [ ] = [ ] // An edge in an augmented path.
15
- const _edges : McmfEdge [ ] = [ ]
23
+ const _edges : IMcmfEdge [ ] = [ ]
16
24
const _G : number [ ] [ ] = [ ]
17
25
const _Q : ICircularQueue < number > = createCircularQueue ( )
18
26
return { init, addEdge, minCostMaxFlow, solve }
@@ -50,8 +58,8 @@ export function createMcmf(): Mcmf {
50
58
}
51
59
52
60
function minCostMaxFlow ( ) : [ number , number ] {
53
- while ( spfa ( ) ) {
54
- let mif = Number . MAX_SAFE_INTEGER
61
+ while ( bellmanFord ( ) ) {
62
+ let mif = _INF
55
63
for ( let o = _target ; o !== _source ; ) {
56
64
const e = _edges [ _path [ o ] ]
57
65
const remainCap = e . cap - e . flow
@@ -70,8 +78,8 @@ export function createMcmf(): Mcmf {
70
78
return [ _mincost , _maxflow ]
71
79
}
72
80
73
- function solve ( fn : ( context : McmfContext ) => void ) : void {
74
- const context : McmfContext = {
81
+ function solve ( fn : ( context : IMcmfContext ) => void ) : void {
82
+ const context : IMcmfContext = {
75
83
edgeTot : _edgeTot ,
76
84
dist : _dist ,
77
85
edges : _edges ,
@@ -80,9 +88,13 @@ export function createMcmf(): Mcmf {
80
88
fn ( context )
81
89
}
82
90
83
- function spfa ( ) : boolean {
91
+ /**
92
+ * Negative loops should not appear in the residual network,
93
+ * so there is no need to check if there are negative loops.
94
+ */
95
+ function bellmanFord ( ) : boolean {
84
96
// Initialize the dist array.
85
- _dist . fill ( - 1 , 0 , _n )
97
+ _dist . fill ( _INF , 0 , _n )
86
98
87
99
_Q . enqueue ( _source )
88
100
_dist [ _source ] = 0
@@ -95,7 +107,7 @@ export function createMcmf(): Mcmf {
95
107
if ( e . cap === e . flow ) continue
96
108
97
109
const candidateDist = _dist [ o ] + e . cost
98
- if ( _dist [ e . to ] === - 1 || _dist [ e . to ] > candidateDist ) {
110
+ if ( _dist [ e . to ] > candidateDist ) {
99
111
_dist [ e . to ] = candidateDist
100
112
_path [ e . to ] = x
101
113
@@ -107,6 +119,6 @@ export function createMcmf(): Mcmf {
107
119
_inq [ o ] = false
108
120
}
109
121
110
- return _dist [ _target ] !== - 1
122
+ return _dist [ _target ] !== _INF
111
123
}
112
124
}
0 commit comments