在我的情况下,我有领土对象。每个地区都知道他们通过阵列连接的其他地区。以下是地图上显示的所有地区的可视化:
如果您要绘制图表上的连接,它们将如下所示:
所以说我有一个驻守在[b]
区域的单位,我想把它移到领土[e]
,我正在寻找一种搜索这个图并返回代表最终数组的方法我的单位在[b]
区域必须采取的路径。在这种情况下,我会寻找它返回
[b, e].
如果我想从领土[a]
到领土[f]
,那么它会返回:
[a, b, e, f].
我会喜欢这样的例子,但即使只是指向我正确方向的帖子也会受到赞赏。提前致谢! :)
答案 0 :(得分:0)
您之前听说过广度优先搜索(BFS)吗?
基本上,您只需将您的初始区域“示例”中的“a”放入另外的空队列中Q
您需要的第二个数据结构是一系列布尔值,其元素与您拥有的区域一样多,在本例中为9.它有助于记住我们已检查过的区域。我们称之为V(对于“已访问”)。它需要初始化如下:除了与初始方块对应的元素外,所有元素都等于false。这适用于所有地区t,我们有V [t] = false,但是V [a] = true,因为“a”已经在队列中。
您需要的第三个也是最后一个数据结构是一个存储父节点的数组(即我们来自哪个节点)。它还拥有与您拥有的区域一样多的元素。我们将其称为P(对于“父”),并且每个元素最初都指向自身,即对于P中的所有t,设置P [t] = t。
然后,这很简单:
while Q is not empty:
t = front element in the queue (remove it also from Q)
if t = f we can break from while loop //because we have found the goal
for all neighbors s of t for which V[s] = false:
add s into the back of Q //we have never explored the territory s yet as V[s] = false
set V[s] = true //we do not have to visit s again in the future
//we found s because there is a connection from t to s
//therefore, we need to remember that in s we are coming from the node t
//to do this we simply set the parent of s to t:
P[s] = t
你现在如何阅读解决方案?
只需检查f的父级,然后检查其父级,然后检查其父级,依此类推,直到找到开头。一旦找到一个自己作为父元素的元素,你就会知道它的起点是什么(记住我们最初让它们指向自己),或者你也可以将它与a进行比较。 基本上,你只需要一个空列表L,在其中添加f然后
while f != a:
f = P[f]
add f into L
请注意,如果没有路径,这显然会失败,因为f永远不会等于a。 因此,这个:
while f != P[f]:
f = P[f]
add f into L
有点好。它利用了这样一个事实,即最初所有地区都指向P。
如果您在上面的示例中尝试使用纸张,那么您最终会得到 L = [f,e,b,a] 如果您只是反转此列表,那么您就拥有了所需的内容。
我不知道C#,所以我不打算使用C#语法。我假设你知道用整数索引你的地区是最简单的,然后使用数组来访问它们。
你会很快意识到为什么会这样。它被称为广度优先搜索,因为您首先只考虑区域“a”的邻居,只有最短的路径(只有1条边),只有处理了所有这些后,才会出现更远的区域(从现在开始只有2个边缘),依此类推。这就是我们为此任务使用队列而不是堆栈的原因。
此外,这是区域和边缘数量的线性,因为您只需要查看每个区域和边缘(最多)一次(尽管来自两个方向的边缘)。
我给你的算法与https://en.wikipedia.org/wiki/Breadth-first_search基本相同,只添加了P数据结构,以便跟踪你来自哪里,以便能够找出所采用的路径。