add MinimumSpanningTree
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- add Prim's mst - add Kruskal's mst - edit weight interface - add exercise directed cycle
This commit is contained in:
parent
cb60157dd1
commit
33710b1391
88
doc/exercises/directed_cycle.md
Normal file
88
doc/exercises/directed_cycle.md
Normal file
@ -0,0 +1,88 @@
|
||||
---
|
||||
author: Raffaele Mignone
|
||||
title: Caratterizzazione della complessità di un algoritmo per la ricerca di cicli orientati in un grafo
|
||||
keywords:
|
||||
- Complessità
|
||||
- Grafo
|
||||
- Ciclo
|
||||
subject: Caratterizzazione della complessità
|
||||
papersize: a4
|
||||
lang: it-IT
|
||||
---
|
||||
|
||||
# Ricerca di cicli orientati
|
||||
|
||||
## Traccia
|
||||
|
||||
Scrivere un programma per la ricerca di directed cycles in un grafo orientato.
|
||||
|
||||
## Soluzione
|
||||
|
||||
Il problema può essere risolto prendendo come base la ricerca in profondità classica.
|
||||
Ad essa deve essere aggiunto un modo per tenere memoria dei nodi presenti sul percorso che si sta esplorando.
|
||||
Ciò può essere fatto tramite l'uso di un array così come si è fatto per tenere traccia dei nodi visitati[^vertex-info].
|
||||
|
||||
[^vertex-info]: Nel caso specifico si è utilizzata una data class che conserva le informazioni `isVisited`, `isOnPath` e `previously`.
|
||||
|
||||
```{#lst:cycle .kotlin caption="Versione modificata della ricerca in profondità"}
|
||||
private fun dfs(graph: UndirectedGraph, vertex: Int) {
|
||||
graphInfo[vertex].isVisited = true
|
||||
graphInfo[vertex].isOnPath = true
|
||||
|
||||
graph.adjacentVertex(vertex)
|
||||
.forEach {
|
||||
when {
|
||||
hasCycle() -> return@forEach
|
||||
!graphInfo[it].isVisited -> exploreChild(graph, vertex, it)
|
||||
graphInfo[it].isOnStack -> cycle = makeCycle(vertex, it)
|
||||
}
|
||||
}
|
||||
|
||||
graphInfo[vertex].isOnPath = false
|
||||
}
|
||||
```
|
||||
|
||||
Quando tra i vertici adiacenti a quello che si sta esplorando si trova un nodo già presente sul percorso vuol dire che è stato trovato un ciclo.
|
||||
La costruzione del ciclo viene mostrata nel @lst:makeCycle
|
||||
|
||||
```{#lst:makeCycle .kotlin caption="Memorizzazione dei vertici che danno origine ad un ciclo"}
|
||||
private fun makeCycle(
|
||||
start: Int,
|
||||
end: Int
|
||||
): MutableCollection<Int> {
|
||||
val cycle = Stack<Int>()
|
||||
|
||||
var currentVertex = start
|
||||
|
||||
while (currentVertex != end) {
|
||||
cycle.add(currentVertex)
|
||||
currentVertex = graphInfo[currentVertex].previously
|
||||
}
|
||||
|
||||
cycle.add(end)
|
||||
cycle.add(start)
|
||||
|
||||
return cycle
|
||||
}
|
||||
```
|
||||
|
||||
Infine la funzione `exploreChild` (@lst:exploreChild) semplicemente si occupa di settare il predecessore e di eseguire la ricerca in profondità sul nuovo vertice.
|
||||
|
||||
```{#lst:exploreChild .kotlin caption="Funzione per eseguire la ricerca in profondità su un vertice adiacente"}
|
||||
private fun exploreChild(
|
||||
graph: UndirectedGraph,
|
||||
parent: Int,
|
||||
child: Int
|
||||
) {
|
||||
graphInfo[child].previously = parent
|
||||
dfs(graph, child)
|
||||
}
|
||||
```
|
||||
|
||||
## Complessità
|
||||
|
||||
L'algoritmo per l'individuazione dei grafi mostrato precedentemente è sostanzialmente una versione modificata della ricerca in profondità e nel caso peggiore deve visitare tutti i nodi percorrendo tutti gli archi, per cui ha una complessità pari a $E + V$.
|
||||
|
||||
## Source code
|
||||
|
||||
- [DirectedCycle](https://git.norangeb.it/norangebit-unisannio-computer-science/lm-tecniche-di-programmazione/src/branch/master/src/main/kotlin/it/norangeb/algorithms/graph/operations/DirectedCycle.kt)
|
@ -43,6 +43,7 @@ interface WeightUndirectedGraph {
|
||||
fun edgeNumber(): Int
|
||||
fun addEdge(edge: EdgeI)
|
||||
fun adjacentVertex(vertex: Int): Collection<EdgeI>
|
||||
fun edges(): Collection<EdgeI>
|
||||
}
|
||||
|
||||
interface WeightDirectedGraph : WeightUndirectedGraph {
|
||||
|
@ -52,4 +52,15 @@ class WeightDiGraph(
|
||||
|
||||
return reverse
|
||||
}
|
||||
|
||||
override fun edges(): Collection<EdgeI> {
|
||||
val edges = mutableListOf<EdgeI>()
|
||||
|
||||
(0 until data.vertexNumber())
|
||||
.forEach {
|
||||
edges.addAll(adjacentVertex(it))
|
||||
}
|
||||
|
||||
return edges
|
||||
}
|
||||
}
|
@ -42,4 +42,15 @@ class WeightGraph(
|
||||
}
|
||||
|
||||
override fun adjacentVertex(vertex: Int): Collection<EdgeI> = data.adjacent(vertex)
|
||||
|
||||
override fun edges(): Collection<EdgeI> {
|
||||
val edges = mutableListOf<EdgeI>()
|
||||
|
||||
(0 until data.vertexNumber())
|
||||
.forEach {
|
||||
edges.addAll(adjacentVertex(it))
|
||||
}
|
||||
|
||||
return edges
|
||||
}
|
||||
}
|
@ -35,8 +35,15 @@ data class Edge(val from: Int, val to: Int, val weight: Double) : EdgeI {
|
||||
else -> from
|
||||
}
|
||||
|
||||
override fun compareTo(other: EdgeI): Int =
|
||||
this.weight.compareTo(other.weight())
|
||||
override fun compareTo(other: EdgeI): Int {
|
||||
var result = weight().compareTo(other.weight())
|
||||
if (result == 0)
|
||||
result = either().compareTo(other.either())
|
||||
if (result == 0)
|
||||
result = other(either()).compareTo(other.other(other.either()))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun reversed(): EdgeI = Edge(to, from, weight)
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019 norangebit
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package it.norangeb.algorithms.graph.operations
|
||||
|
||||
import it.norangeb.algorithms.datastructures.queue.priority.BinaryHeap
|
||||
import it.norangeb.algorithms.datastructures.queue.priority.PriorityQueue
|
||||
import it.norangeb.algorithms.datastructures.unionfind.QuickFind
|
||||
import it.norangeb.algorithms.datastructures.unionfind.UnionFind
|
||||
import it.norangeb.algorithms.graph.WeightUndirectedGraph
|
||||
import it.norangeb.algorithms.graph.data.EdgeI
|
||||
|
||||
class Kruskal(graph: WeightUndirectedGraph) : MinimumSpanningTree {
|
||||
val mst = mutableListOf<EdgeI>()
|
||||
|
||||
init {
|
||||
val minQueue = BinaryHeap.createMinPriorityQueue<EdgeI>()
|
||||
val unionFindGraph = QuickFind(graph.vertexNumber())
|
||||
|
||||
graph.edges().forEach { minQueue.insert(it) }
|
||||
|
||||
while (!minQueue.isEmpty() && mst.size < graph.vertexNumber() - 1)
|
||||
tryEdge(minQueue, unionFindGraph)
|
||||
}
|
||||
|
||||
private fun tryEdge(heap: PriorityQueue<EdgeI>, unionFindGraph: UnionFind) {
|
||||
heap.pop().map {
|
||||
val from = it.either()
|
||||
val to = it.other(from)
|
||||
|
||||
if (!unionFindGraph.connected(from, to)) {
|
||||
unionFindGraph.union(from, to)
|
||||
mst.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun edges(): Collection<EdgeI> = mst
|
||||
|
||||
override fun weight(): Double = mst.map { it.weight() }.sum()
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019 norangebit
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package it.norangeb.algorithms.graph.operations
|
||||
|
||||
import it.norangeb.algorithms.graph.data.EdgeI
|
||||
|
||||
interface MinimumSpanningTree {
|
||||
fun edges(): Collection<EdgeI>
|
||||
fun weight(): Double
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019 norangebit
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package it.norangeb.algorithms.graph.operations
|
||||
|
||||
import it.norangeb.algorithms.datastructures.queue.priority.BinaryHeap
|
||||
import it.norangeb.algorithms.datastructures.queue.priority.PriorityQueue
|
||||
import it.norangeb.algorithms.graph.WeightUndirectedGraph
|
||||
import it.norangeb.algorithms.graph.data.EdgeI
|
||||
|
||||
class Prim(graph: WeightUndirectedGraph) : MinimumSpanningTree {
|
||||
private val mst = mutableListOf<EdgeI>()
|
||||
private val visited = Array(graph.vertexNumber()) { false }
|
||||
|
||||
init {
|
||||
val queue = BinaryHeap.createMinPriorityQueue<EdgeI>()
|
||||
|
||||
visitAdjacent(graph, 0, queue)
|
||||
|
||||
while (!queue.isEmpty() && mst.size < graph.vertexNumber() - 1)
|
||||
tryEdge(graph, queue)
|
||||
}
|
||||
|
||||
private fun tryEdge(graph: WeightUndirectedGraph, heap: PriorityQueue<EdgeI>) {
|
||||
heap.pop().map {
|
||||
val from = it.either()
|
||||
val to = it.other(from)
|
||||
|
||||
if (visited[from] && visited[to])
|
||||
return@map
|
||||
if (!visited[from])
|
||||
visitAdjacent(graph, from, heap)
|
||||
if (!visited[to])
|
||||
visitAdjacent(graph, to, heap)
|
||||
|
||||
mst.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitAdjacent(
|
||||
graph: WeightUndirectedGraph,
|
||||
vertex: Int,
|
||||
heap: PriorityQueue<EdgeI>
|
||||
) {
|
||||
visited[vertex] = true
|
||||
|
||||
graph.adjacentVertex(vertex)
|
||||
.forEach {
|
||||
if (!visited[it.other(vertex)])
|
||||
heap.insert(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun edges(): Collection<EdgeI> = mst
|
||||
|
||||
override fun weight(): Double = mst.map { it.weight() }.sum()
|
||||
}
|
@ -73,6 +73,15 @@ object WeightDiGraphTest : Spek({
|
||||
Then("adjacent of 3 should equal listOf(3->4:3.4)") {
|
||||
graph.adjacentVertex(3) `should equal` listOf(Edge(3, 4, 3.4))
|
||||
}
|
||||
|
||||
Then("edges should equals listOf(1->3:1.3, 1->4:1.4, 1->5:1.5, 3->4:3.4") {
|
||||
graph.edges().sorted() `should equal` listOf(
|
||||
Edge(1, 3, 1.3),
|
||||
Edge(1, 4, 1.4),
|
||||
Edge(1, 5, 1.5),
|
||||
Edge(3, 4, 3.4)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Scenario("reverse test") {
|
||||
|
@ -76,6 +76,20 @@ object WeightGraphTest : Spek({
|
||||
Edge(3, 4, 3.4)
|
||||
)
|
||||
}
|
||||
|
||||
Then("edges should equals listOf(1->3:1.3, 1->5:1.5, 3->4:3.4, 1->4:5.0,") {
|
||||
graph.edges().sorted() `should equal` listOf(
|
||||
Edge(1, 3, 1.1),
|
||||
Edge(3, 1, 1.1),
|
||||
Edge(1, 5, 1.5),
|
||||
Edge(5, 1, 1.5),
|
||||
Edge(3, 4, 3.4),
|
||||
Edge(4, 3, 3.4),
|
||||
Edge(1, 4, 5.0),
|
||||
Edge(4, 1, 5.0)
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019 norangebit
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package it.norangeb.algorithms.graph.operations
|
||||
|
||||
import it.norangeb.algorithms.graph.WeightGraph
|
||||
import it.norangeb.algorithms.graph.data.Edge
|
||||
import org.amshove.kluent.`should be equal to`
|
||||
import org.amshove.kluent.`should equal`
|
||||
import org.spekframework.spek2.Spek
|
||||
import org.spekframework.spek2.style.gherkin.Feature
|
||||
|
||||
object KruskalTest : Spek({
|
||||
Feature("kruskal") {
|
||||
Scenario("compute mst") {
|
||||
val graph by memoized { WeightGraph() }
|
||||
|
||||
Given("a graph") {
|
||||
graph.addEdge(Edge(0, 2, 0.26))
|
||||
graph.addEdge(Edge(0, 4, 0.38))
|
||||
graph.addEdge(Edge(0, 7, 0.16))
|
||||
graph.addEdge(Edge(1, 2, 0.36))
|
||||
graph.addEdge(Edge(1, 3, 0.29))
|
||||
graph.addEdge(Edge(1, 5, 0.32))
|
||||
graph.addEdge(Edge(1, 7, 0.19))
|
||||
graph.addEdge(Edge(2, 3, 0.17))
|
||||
graph.addEdge(Edge(2, 7, 0.34))
|
||||
graph.addEdge(Edge(3, 6, 0.52))
|
||||
graph.addEdge(Edge(4, 5, 0.35))
|
||||
graph.addEdge(Edge(4, 7, 0.37))
|
||||
graph.addEdge(Edge(5, 7, 0.28))
|
||||
graph.addEdge(Edge(6, 2, 0.40))
|
||||
}
|
||||
|
||||
lateinit var result: MinimumSpanningTree
|
||||
|
||||
When("compute the mst") {
|
||||
result = Kruskal(graph)
|
||||
}
|
||||
|
||||
Then("weight should be 1.81") {
|
||||
result.weight() `should be equal to` 1.81
|
||||
}
|
||||
|
||||
Then("edge should be") {
|
||||
result.edges() `should equal` listOf(
|
||||
Edge(0, 7, 0.16),
|
||||
Edge(2, 3, 0.17),
|
||||
Edge(1, 7, 0.19),
|
||||
Edge(0, 2, 0.26),
|
||||
Edge(5, 7, 0.28),
|
||||
Edge(4, 5, 0.35),
|
||||
Edge(2, 6, 0.40)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019 norangebit
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package it.norangeb.algorithms.graph.operations
|
||||
|
||||
import it.norangeb.algorithms.graph.WeightGraph
|
||||
import it.norangeb.algorithms.graph.data.Edge
|
||||
import org.amshove.kluent.`should be equal to`
|
||||
import org.amshove.kluent.`should equal`
|
||||
import org.spekframework.spek2.Spek
|
||||
import org.spekframework.spek2.style.gherkin.Feature
|
||||
|
||||
object PrimTest : Spek({
|
||||
Feature("prim") {
|
||||
Scenario("compute mst") {
|
||||
val graph by memoized { WeightGraph() }
|
||||
|
||||
Given("a graph") {
|
||||
graph.addEdge(Edge(0, 2, 0.26))
|
||||
graph.addEdge(Edge(0, 4, 0.38))
|
||||
graph.addEdge(Edge(0, 7, 0.16))
|
||||
graph.addEdge(Edge(1, 2, 0.36))
|
||||
graph.addEdge(Edge(1, 3, 0.29))
|
||||
graph.addEdge(Edge(1, 5, 0.32))
|
||||
graph.addEdge(Edge(1, 7, 0.19))
|
||||
graph.addEdge(Edge(2, 3, 0.17))
|
||||
graph.addEdge(Edge(2, 7, 0.34))
|
||||
graph.addEdge(Edge(3, 6, 0.52))
|
||||
graph.addEdge(Edge(4, 5, 0.35))
|
||||
graph.addEdge(Edge(4, 7, 0.37))
|
||||
graph.addEdge(Edge(5, 7, 0.28))
|
||||
graph.addEdge(Edge(6, 2, 0.40))
|
||||
}
|
||||
|
||||
lateinit var result: MinimumSpanningTree
|
||||
|
||||
When("compute the mst") {
|
||||
result = Prim(graph)
|
||||
}
|
||||
|
||||
Then("weight should be 1.81") {
|
||||
result.weight() `should be equal to` 1.81
|
||||
}
|
||||
|
||||
Then("edge should be") {
|
||||
result.edges().sorted() `should equal` listOf(
|
||||
Edge(0, 7, 0.16),
|
||||
Edge(2, 3, 0.17),
|
||||
Edge(7, 1, 0.19),
|
||||
Edge(0, 2, 0.26),
|
||||
Edge(7, 5, 0.28),
|
||||
Edge(5, 4, 0.35),
|
||||
Edge(2, 6, 0.40)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user