graph/path: do not keep duplicate paths in YenKShortestPaths

Previously the code did not ignore spur paths that had already been added into
the list of potential paths. This could cause the search to return duplicate
paths for certain graphs.
This commit is contained in:
Eng Zer Jun
2023-11-08 11:42:31 +08:00
committed by GitHub
parent 5e05b17912
commit db43f45c2b
2 changed files with 47 additions and 1 deletions

View File

@@ -85,7 +85,18 @@ func YenKShortestPaths(g graph.Graph, k int, cost float64, s, t graph.Node) [][]
spath = append(root[:len(root)-1], spath...)
weight += rootWeight
}
pot = append(pot, yenShortest{spath, weight})
// Add the potential k-shortest path if it is new.
isNewPot := true
for x := range pot {
if isSamePath(pot[x].path, spath) {
isNewPot = false
break
}
}
if isNewPot {
pot = append(pot, yenShortest{spath, weight})
}
}
if len(pot) == 0 {
@@ -104,6 +115,19 @@ func YenKShortestPaths(g graph.Graph, k int, cost float64, s, t graph.Node) [][]
return paths
}
func isSamePath(a, b []graph.Node) bool {
if len(a) != len(b) {
return false
}
for i, x := range a {
if x.ID() != b[i].ID() {
return false
}
}
return true
}
// yenShortest holds a path and its weight for sorting.
type yenShortest struct {
path []graph.Node

View File

@@ -306,6 +306,28 @@ var yenShortestPathTests = []struct {
{8, 2, 4, 3, 7, 5},
},
},
{
name: "grid", // This is the failing case in gonum/gonum#1920.
graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) },
edges: []simple.WeightedEdge{
{F: simple.Node(1), T: simple.Node(2), W: 1},
{F: simple.Node(2), T: simple.Node(3), W: 2},
{F: simple.Node(3), T: simple.Node(6), W: 5},
{F: simple.Node(1), T: simple.Node(4), W: 5},
{F: simple.Node(2), T: simple.Node(5), W: 4},
{F: simple.Node(4), T: simple.Node(5), W: 6},
{F: simple.Node(5), T: simple.Node(6), W: 7},
},
query: simple.Edge{F: simple.Node(1), T: simple.Node(6)},
k: -1,
cost: math.Inf(1),
wantPaths: [][]int64{
{1, 2, 3, 6},
{1, 2, 5, 6},
{1, 4, 5, 6},
{1, 4, 5, 2, 3, 6},
},
},
}
func bipartite(n int, weight, inc float64) []simple.WeightedEdge {