@algorithm.ts/mcmf
Version:
The MCMF algorithm implemented in typescript
233 lines (193 loc) • 6.66 kB
Markdown
<header>
<h1 align="center">
<a href="https://github.com/guanghechen/algorithm.ts/tree/@algorithm.ts/mcmf@4.0.4/packages/mcmf#readme">@algorithm.ts/mcmf</a>
</h1>
<div align="center">
<a href="https://www.npmjs.com/package/@algorithm.ts/mcmf">
<img
alt="Npm Version"
src="https://img.shields.io/npm/v/@algorithm.ts/mcmf.svg"
/>
</a>
<a href="https://www.npmjs.com/package/@algorithm.ts/mcmf">
<img
alt="Npm Download"
src="https://img.shields.io/npm/dm/@algorithm.ts/mcmf.svg"
/>
</a>
<a href="https://www.npmjs.com/package/@algorithm.ts/mcmf">
<img
alt="Npm License"
src="https://img.shields.io/npm/l/@algorithm.ts/mcmf.svg"
/>
</a>
<a href="#install">
<img
alt="Module Formats: cjs, esm"
src="https://img.shields.io/badge/module_formats-cjs%2C%20esm-green.svg"
/>
</a>
<a href="https://github.com/nodejs/node">
<img
alt="Node.js Version"
src="https://img.shields.io/node/v/@algorithm.ts/mcmf"
/>
</a>
<a href="https://github.com/facebook/jest">
<img
alt="Tested with Jest"
src="https://img.shields.io/badge/tested_with-jest-9c465e.svg"
/>
</a>
<a href="https://github.com/prettier/prettier">
<img
alt="Code Style: prettier"
src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square"
/>
</a>
</div>
</header>
<br/>
A typescript implementation of the **MCMF (Min Cost Max Flow)** algorithm.
The **MCMF** algorithm is an algorithm for solving network flow problems.
## Install
- npm
```bash
npm install --save @algorithm.ts/mcmf
```
- yarn
```bash
yarn add @algorithm.ts/mcmf
```
## Usage
- Codeforces contest 0277 Problem E (https://codeforces.com/contest/277/problem/E):
```typescript
import { Mcmf } from '@algorithm.ts/mcmf'
const mcmf = new Mcmf()
export function solveCodeforces0277E(coordinates: Array<[x: number, y: number]>): number {
const N: number = coordinates.length
const vertexes: IVertex[] = coordinates
.map(([x, y]) => ({ x, y }))
.sort((p, q) => {
if (p.y === q.y) return p.x - q.x
return q.y - p.y
})
const source = 0
const target: number = N * 2 + 1
mcmf.init(source, target, N * 2 + 2)
for (let i = 0; i < N; ++i) {
mcmf.addEdge(source, i + 1, 2, 0)
mcmf.addEdge(N + i + 1, target, 1, 0)
for (let j = i + 1; j < N; ++j) {
if (vertexes[i].y === vertexes[j].y) continue
mcmf.addEdge(i + 1, N + j + 1, 1, dist(vertexes[i], vertexes[j]))
}
}
const { mincost, maxflow } = mcmf.minCostMaxFlow()
const answer = maxflow === N - 1 ? mincost : -1
return answer
}
function dist(p: IVertex, q: IVertex): number {
const d = (p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y)
return Math.sqrt(d)
}
interface IVertex {
x: number
y: number
}
```
- A solution for Codeforces contest 1082 Problem G (https://codeforces.com/contest/1082/problem/G):
```typescript
import { Mcmf } from '@algorithm.ts/mcmf'
const mcmf = new Mcmf()
export function solveCodeforces1082G(
nodes: number[],
edges: Array<[u: number, v: number, weight: number]>,
): number {
const n: number = nodes.length
const m: number = edges.length
const source = 0
const target: number = n + m + 1
mcmf.init(source, target, n + m + 2)
for (let i = 0; i < n; ++i) {
const weight: number = nodes[i]
mcmf.addEdge(i + 1, target, weight, 0)
}
let answer = 0
for (let i = 0; i < m; ++i) {
const [u, v, weight] = edges[i]
const x = n + i
answer += weight
mcmf.addEdge(source, x, weight, 0)
mcmf.addEdge(x, u, Number.MAX_SAFE_INTEGER, 0)
mcmf.addEdge(x, v, Number.MAX_SAFE_INTEGER, 0)
}
const { mincost, maxflow } = mcmf.minCostMaxFlow()
answer -= maxflow
return answer
}
```
- A solution for leetcode "Maximum Students Taking Exam"
(https://leetcode.com/problems/maximum-students-taking-exam/):
```typescript
import { Mcmf } from '@algorithm.ts/mcmf'
export function maxStudents(seats: string[][]): number {
const R: number = seats.length
if (R <= 0) return 0
const C: number = seats[0].length
if (C <= 0) return 0
let total = 0
const seatCodes: number[][] = new Array(R)
for (let r = 0; r < R; ++r) seatCodes[r] = new Array(C).fill(-1)
for (let r = 0; r < R; ++r) {
for (let c = 0; c < C; ++c) {
if (seats[r][c] === '.') seatCodes[r][c] = total++
}
}
if (total <= 0) return 0
if (total === 1) return 1
const source: number = total * 2
const target: number = source + 1
const mcmf = new Mcmf()
mcmf.init(source, target, target + 1)
for (let r = 0; r < R; ++r) {
for (let c = 0; c < C; ++c) {
const u: number = seatCodes[r][c]
if (u > -1) {
mcmf.addEdge(source, u, 1, 0)
mcmf.addEdge(u + total, target, 1, 0)
if (r > 0) {
// Check upper left
if (c > 0 && seatCodes[r - 1][c - 1] > -1) {
const v: number = seatCodes[r - 1][c - 1]
mcmf.addEdge(u, v + total, 1, 0)
mcmf.addEdge(v, u + total, 1, 0)
}
// Check upper right
if (c + 1 < C && seatCodes[r - 1][c + 1] > -1) {
const v: number = seatCodes[r - 1][c + 1]
mcmf.addEdge(u, v + total, 1, 0)
mcmf.addEdge(v, u + total, 1, 0)
}
}
// Check left
if (c > 0 && seatCodes[r][c - 1] > -1) {
const v: number = seatCodes[r][c - 1]
mcmf.addEdge(u, v + total, 1, 0)
mcmf.addEdge(v, u + total, 1, 0)
}
}
}
}
const { mincost, maxflow } = mcmf.minCostMaxFlow()
const totalPaired: number = maxflow / 2
return total - totalPaired
}
```
## Related
- [@algorithm.ts/dinic](https://github.com/guanghechen/algorithm.ts/tree/@algorithm.ts/dinic@4.0.4/packages/dinic)
- [@algorithm.ts/mcmf](https://github.com/guanghechen/algorithm.ts/tree/@algorithm.ts/mcmf@4.0.4/packages/mcmf)
- [网络流 24 题](https://me.guanghechen.com/post/algorithm/graph/network-flow/24-problems/)
- [网络流基础之最大权闭合图](https://me.guanghechen.com/post/algorithm/graph/network-flow/%E6%9C%80%E5%A4%A7%E6%9D%83%E9%97%AD%E5%90%88%E5%9B%BE/)
[homepage]:
https://github.com/guanghechen/algorithm.ts/tree/@algorithm.ts/mcmf@4.0.4/packages/mcmf#readme