Skip to content

Commit 4fbcbdc

Browse files
committed
🎨 improve(mcmf): update types & improve shortest-path algorithm
1 parent f3f0807 commit 4fbcbdc

File tree

2 files changed

+34
-19
lines changed

2 files changed

+34
-19
lines changed

Diff for: packages/mcmf/src/mcmf.ts

+23-11
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import type { ICircularQueue } from '@algorithm.ts/circular-queue'
22
import { createCircularQueue } from '@algorithm.ts/circular-queue'
3-
import type { Mcmf, McmfContext, McmfEdge } from './types'
3+
import type { IMcmf, IMcmfContext, IMcmfEdge } from './types'
44

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 {
613
let _source: number // The source point in a network flow
714
let _target: number // The sink in a network flow
815
let _n: number // The number of nodes in a network flow
916
let _mincost: number
1017
let _maxflow: number
1118
let _edgeTot: number
19+
const _INF: number = options.INF ?? Number.MAX_VALUE / 2
1220
const _inq: boolean[] = [] // Whether if the i-th node is in the queue.
1321
const _dist: number[] = [] // The distance from the source node to the i-th node.
1422
const _path: number[] = [] // An edge in an augmented path.
15-
const _edges: McmfEdge[] = []
23+
const _edges: IMcmfEdge[] = []
1624
const _G: number[][] = []
1725
const _Q: ICircularQueue<number> = createCircularQueue()
1826
return { init, addEdge, minCostMaxFlow, solve }
@@ -50,8 +58,8 @@ export function createMcmf(): Mcmf {
5058
}
5159

5260
function minCostMaxFlow(): [number, number] {
53-
while (spfa()) {
54-
let mif = Number.MAX_SAFE_INTEGER
61+
while (bellmanFord()) {
62+
let mif = _INF
5563
for (let o = _target; o !== _source; ) {
5664
const e = _edges[_path[o]]
5765
const remainCap = e.cap - e.flow
@@ -70,8 +78,8 @@ export function createMcmf(): Mcmf {
7078
return [_mincost, _maxflow]
7179
}
7280

73-
function solve(fn: (context: McmfContext) => void): void {
74-
const context: McmfContext = {
81+
function solve(fn: (context: IMcmfContext) => void): void {
82+
const context: IMcmfContext = {
7583
edgeTot: _edgeTot,
7684
dist: _dist,
7785
edges: _edges,
@@ -80,9 +88,13 @@ export function createMcmf(): Mcmf {
8088
fn(context)
8189
}
8290

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 {
8496
// Initialize the dist array.
85-
_dist.fill(-1, 0, _n)
97+
_dist.fill(_INF, 0, _n)
8698

8799
_Q.enqueue(_source)
88100
_dist[_source] = 0
@@ -95,7 +107,7 @@ export function createMcmf(): Mcmf {
95107
if (e.cap === e.flow) continue
96108

97109
const candidateDist = _dist[o] + e.cost
98-
if (_dist[e.to] === -1 || _dist[e.to] > candidateDist) {
110+
if (_dist[e.to] > candidateDist) {
99111
_dist[e.to] = candidateDist
100112
_path[e.to] = x
101113

@@ -107,6 +119,6 @@ export function createMcmf(): Mcmf {
107119
_inq[o] = false
108120
}
109121

110-
return _dist[_target] !== -1
122+
return _dist[_target] !== _INF
111123
}
112124
}

Diff for: packages/mcmf/src/types.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* 残量网络中的一条弧
33
* An arc in the residual network.
44
*/
5-
export interface McmfEdge {
5+
export interface IMcmfEdge {
66
/**
77
* The starting node of the arc.
88
*/
@@ -25,26 +25,29 @@ export interface McmfEdge {
2525
cost: number
2626
}
2727

28-
export interface McmfContext {
28+
export interface IMcmfContext {
2929
/**
30+
* The number of valid edges.
3031
*
32+
* In order to save space, there is not recreate a new array at each `init()` called, so this
33+
* field is used to record the actual effective array length.
3134
*/
3235
edgeTot: number
3336
/**
3437
*
3538
*/
3639
dist: number[]
3740
/**
38-
*
41+
* Graph edges.
3942
*/
40-
edges: McmfEdge[]
43+
edges: ReadonlyArray<IMcmfEdge>
4144
/**
42-
*
45+
* Adjacency list. G[i] represent the index list of the edges start from node i.
4346
*/
44-
G: number[][]
47+
G: ReadonlyArray<ReadonlyArray<number>>
4548
}
4649

47-
export interface Mcmf {
50+
export interface IMcmf {
4851
/**
4952
* Initialize the mcmf algorithm.
5053
* @param source the source node
@@ -74,5 +77,5 @@ export interface Mcmf {
7477
* will be passed into the callback function as parameters.
7578
* @param fn
7679
*/
77-
solve(fn: (context: McmfContext) => void): void
80+
solve(fn: (context: IMcmfContext) => void): void
7881
}

0 commit comments

Comments
 (0)