JavaScript 算法 : print out the path from directed graph with minimal costs

标签 javascript algorithm breadth-first-search directed-graph

这是一个可以使用在每条边上具有不同成本的有向图来建模的问题。

我们的输入是一个边数组。

const edges = [['A', 'B', 20], ['B', 'C', 10], ['A', 'C', 50], ['B', 'D', 5], ['D', 'C', 2]]

['A', 'B', 20], 表示从 AB 的成本是 20。我想编写一个函数,返回给定地点与成本最低的另一个地点之间的路径。请注意,此图中没有循环

在这种情况下,如果起点是A,终点是C,那么有3条路可以走

path 1: A => C - cost 50
path 2: A => B => C - cost 30
path 3: A => B => D => C - cost 27

所以函数应该返回具有最小成本的路径,即 A, B, D, C

这是我的尝试:

function bar(edges, start, end) {
    const paths = []
    const visited = new Map()
    const graph = edges.reduce((map, [start, end, cost]) => {
        if(map.has(start)) {
            map.get(start).push([end, cost])
        } else {
            map.set(start, [[end, cost]])
        }
        return map
    }, new Map())
    const queue = [[start, 0]]
    for(const [node, costSofar] of queue) {
        if(node === end) {
            let pointer = node
            const path = []
            while(pointer) {
                path.push(pointer)
                pointer = visited.get(pointer)
            }    
            
            paths.push([path.reverse().join(','), costSofar])
            continue
        }
        graph.get(node).forEach(([dest, localCost]) => {
            // this part 👇 is problematic
            visited.set(dest, node)
            queue.push([dest, localCost + costSofar])
            
        })
    }

    return paths.sort(([pathA, costA], [pathB, costB]) => costA - costB)[0]
}

所以我用邻接表来表示图,即

{
    A: [['B', 20], ['C', 50]]
    B: [['C', 10], ['D', 5]]
    D: [['C', 2]]
}

然后我使用广度优先搜索来探索图形并记录路径,一旦我们到达目的地,我们就将路径添加到 paths。顺便说一句,我知道 Dijkstra 算法,但是,如果我错了,请纠正我,我觉得因为这个图没有循环,所以我们可以使用普通的 bfs 来解决它。

我的问题是,我的函数实际上有一个错误,虽然它确实捕获了所有具有相应成本的路径,但路径并非 100% 正确。如果您注销函数的返回语句,即 paths.sort(([pathA, costA], [pathB, costB]) => costA - costB) 您将看到此处的值为 ‹[ [ 'A,B,D,C', 27 ], [ 'A,B,C', 30 ], [ 'A,B,C', 50 ] ]‹ .前两个是正确的,但最后一个应该是 ['A','C', 50]。我认为问题是由填充 visited map 的方式引起的,但我不知道如何解决这个问题。

最佳答案

因为您希望为每条可能的路径维护单独的路径信息,即使一条路径稍后拦截另一条路径,拥有一个 visited 键是目标节点的 Map 也无法解决问题,因为 visited.set 将覆盖之前路径的信息。

我不是在最后使用 visited 获取循环中的指针,而是在迭代时获取 graph Map 的节点信息。递归会有所帮助。

function bar(edges, start, end) {
    const graph = edges.reduce((map, [start, end, cost]) => {
        if(map.has(start)) {
            map.get(start).push([end, cost])
        } else {
            map.set(start, [[end, cost]])
        }
        return map
    }, new Map())
    const paths = [];
    const find = (start, pathSoFar = [start], costSoFar = 0) => {
        for (const [dest, cost] of graph.get(start)) {
            const newPath = pathSoFar.concat(dest);
            if (dest === end) {
                paths.push([newPath.join(','), costSoFar + cost]);
            } else {
                find(dest, newPath, costSoFar + cost);
            }
        }
    };
    find(start);
    
    console.log(paths);
    
    // return paths.sort(([pathA, costA], [pathB, costB]) => costA - costB)[0]
    // or, make it O(n) instead of O(n log n):
    return paths.reduce((a, b) => a[1] > b[1] ? b : a);
}
const edges = [['A', 'B', 20], ['B', 'C', 10], ['A', 'C', 50], ['B', 'D', 5], ['D', 'C', 2]]

console.log(bar(edges, 'A', 'C'));

关于JavaScript 算法 : print out the path from directed graph with minimal costs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66739213/

相关文章:

java - BFS 通过矩阵迷宫陷入循环

javascript - 更改表格列宽

javascript - 根据条件注释/取消注释代码

python - 在 Python 中生成(不完全)跨越集的算法

javascript - Array.reduce的性能

java - 如何在邻接矩阵的广度优先搜索中跟踪每个顶点的深度? ( java )

javascript - 如何制作 jQuery 变量切换按钮?

javascript - node.js、socket.io 运动

node.js - 检测有向图中的循环

python - python中无替换的Word Ladder