您是否听说过广度优先搜索(BFS)?
基本上,你只需把你的初始领土,“一”,在你的榜样,为其他空队列Q
你需要的是布尔值数组与尽可能多的元素,你有领土的第二数据结构,在这种情况下9.它有助于记住我们已经检查过哪些区域。我们称之为V(用于“访问”)。它需要进行如下初始化:除了与初始平方对应的元素之外,所有元素都等于false。对于所有地区t,我们有V [t] = false,但V [a] =真,因为“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永远等于一个不存在的路径,这显然是失败。 因此,这个:
while f != P[f]:
f = P[f]
add f into L
是有点更好。它利用了这样一个事实,即最初所有领土都指向P.
如果你尝试这种在纸上用你上面的例子,那么你将最终 L = [F,E,B,A] 如果你简单地扭转这个列表中,那么你有你想要的东西。
我不知道C#,所以我没有打扰使用C#语法。我假设你知道用整数索引你的领域是最容易的,然后使用一个数组来访问它们。
你会很快意识到为什么这会起作用。这就是所谓的广度优先搜索,因为您首先只考虑领土“a”的邻居,通往他们的路径最短(只有一条边),只有一次处理完所有这些后,距离较远的领域才会出现在队列中从现在开始只有2条边)等等。这就是为什么我们使用队列执行此任务而不是堆栈。
此外,这是领土和边缘数量的线性因为您只需要查看每个领土和边缘(最多)一次(虽然从两个方向的边缘)。
我给你的算法基本上与https://en.wikipedia.org/wiki/Breadth-first_search一样,只添加了P数据结构来跟踪你来自哪里,能够找出所采取的路径。
这是一个梦幻般的回应,我只是想感谢你!我会在这个周末尝试这种方法并回复你。 – slimabob
不客气!如果您遇到任何困难,请告诉我们。 – Eulerson
好的,我知道这有点晚,但我只是有时间来实现这一点,并希望跟进。事情大部分都是正确的,但我有一种感觉,我没有正确地做事情。当我尝试像'[f]'到'[b]'那样做时,一切正常,并且它返回正确的路径,但是如果我尝试''[g]'到'[a]',我会遇到一个无限循环并挂起。我相信这只是一个误解你写的东西的简单例子。 这是我写的:https://pastebin.com/03PWRu9h 这是我的领土类:https://pastebin.com/sq0viDwb – slimabob