我正在尝试实现一种算法,该算法在以下二维数组(从左上角到右下角)中找到最短路径:
[ [ 'A', 'A', 'A', 'B', 'A' ],
[ 'B', 'B', 'B', 'B', 'B' ],
[ 'A', 'B', 'A', 'A', 'A' ],
[ 'A', 'B', 'B', 'B', 'B' ],
[ 'A', 'A', 'A', 'A', 'A' ] ]
规则是,路径必须在A和B之间交替。
输出必须是一个数字,指定通过数组将执行的最小步骤数。 (在示例中,预期输出为13)
有人知道一个简单的Graph实现可以帮助我解决这个问题吗?
答案 0 :(得分:2)
解决问题的一种方法是首先将2D数组表示为图,其中每个字母是一个节点,并且如果两个节点之间的字母在数组中是相邻的,则两个节点之间存在一条边。不同(一个A
和一个B
)。
然后,您要做的就是使用经典的最短路径算法(例如Dijkstra的算法或A *)来查找图形的两个节点之间的最短路径。这等效于找到数组中两个字母之间的最短路径。
编辑: 这是一个伪代码,用于回答您在评论中提出的问题。
nodes = init_a_2d_array_of_graph_nodes(ARRAY_WIDTH, ARRAY_HEIGHT)
for i from 1 to ARRAY_WIDTH:
for j from 1 to ARRAY_HEIGHT:
if i < ARRAY_WIDTH and array[i][j] != array[i+1][j]:
add_edge(nodes[i][j], nodes[i+1][j])
if j < ARRAY_HEIGHT and array[i][j] != array[i][j+1]:
add_edge(nodes[i][j], nodes[i][j+1])
首先,您需要初始化图结构。如果您不知道该怎么做,请在线检查,必须有很多方法可以做到,这很简单。
然后,您需要为数组中的每个字母创建一个节点。将这些节点存储在2D数组中也很方便,因此您可以轻松找出数组的哪个字母对应于图形中的哪个节点。
然后,对于所有邻居字母,请检查这些字母是否不同(这是在2个if
条件中检查的)。如果是这种情况,则将两个节点连接在一起。
此后,您将需要在图上的源节点和目标节点之间运行最短路径算法。 Dijkstra的算法是最短路径算法的最佳入门方法,它是使用最广泛的算法,并且在大多数情况下都足够快。
最后,有了路径后,您需要检索图形节点的索引(行和列),这将为您提供字母数组中的相应路径。
如果仍有您不理解的地方,请随时发表评论。
答案 1 :(得分:2)
好吧,您可以将网格用作图形,而无需将其转换为常用的图形邻接表表示形式。
所以每对(行,列)都是一个节点,
仅在以下情况下,您可以转到下一个节点:2个节点是邻居并且具有不同的值,
邻接表的目的是提高相邻节点的效率,但是使用网格单元,您始终可以始终检查所有4个方向并处理存在的节点。
示例代码:
entityManager.createQuery(...)
答案 2 :(得分:0)
有人知道一个简单的Graph实现可以帮助我解决这个问题吗?
Dijkstra algortihm用于查找两个节点之间的最短路径。二维数组中的每个位置都代表一个节点,边缘是从周围的节点动态派生的,这些节点满足您的“替代”规则。
您可以通过双向搜索和目标指标(A *)为您的用例further optimise。
答案 3 :(得分:0)
由于它表示无向 未加权图,因此您可以简单地使用BFS:
const m =
[ [ 'A', 'A', 'A', 'B', 'A' ],
[ 'B', 'B', 'B', 'B', 'B' ],
[ 'A', 'B', 'A', 'A', 'A' ],
[ 'A', 'B', 'B', 'B', 'B' ],
[ 'A', 'A', 'A', 'A', 'A' ] ]
let successors = (root, m) => {
let connectedCells = [
[root[0] - 1, root[1]],
[root[0], root[1] - 1],
[root[0] + 1, root[1]],
[root[0], root[1] + 1]
]
const validCells = connectedCells.filter(
(cell) => (
cell[0] >= 0 && cell[0] < m.length
&& cell[1] >= 0 && cell[1] < m[0].length)
)
const successors = validCells.filter(
(cell) => (m[cell[0]][cell[1]] !== m[root[0]][root[1]])
)
return successors
}
const buildPath = (traversalTree, to) => {
let path = [to]
let parent = traversalTree[to]
while (parent) {
path.push(parent)
parent = traversalTree[parent]
}
return path.reverse()
}
const bfs = (from, to) => {
let traversalTree = []
let visited = new Set
let queue = []
queue.push(from)
while (queue.length) {
let subtreeRoot = queue.shift()
visited.add(subtreeRoot.toString())
if (subtreeRoot.toString() == to.toString()) return buildPath(traversalTree, to)
for (child of successors(subtreeRoot, m)) {
if (!visited.has(child.toString())){
traversalTree[child] = subtreeRoot
queue.push(child)
}
}
}
}
console.log(bfs([0,0], [4,4]).length) // => 13