路径查找算法,坚持基础

时间:2011-04-22 06:54:25

标签: algorithm

这是一个基本的大学拼图问题,我虽然我会指出,但是当涉及到实施它时,我就被卡住了。

背景:4位路径寻找算法,因此例如给出目标号1001和目标号1040,使用BF,DF等等找到路径。

允许移动:按任意顺序从4位中的任何一位加1或减1,你不能加9,或从0减去。你不能在同一位数上加或减两次,即得到1000到3000,你不能做2000 - > 3000,因为你将在第一个数字上加两次。所以你必须做2000-> 2100-> 3100-> 3000。

我陷入困境:我无法弄清楚我将如何以编程方式表示问题,更不用说算法,但我将如何代表1001并向1004迈进。什么数据结构?我如何识别邻居?

有人可以把我推向正确的方向吗?

5 个答案:

答案 0 :(得分:2)

如果我理解正确,您正在寻找一种方法来表示您的问题。也许你很难找到它,因为问题使用的是4位数。尝试缩小尺寸,并考虑2位数的相同问题(另请参阅this other answer)。假设您想使用问题规则从10移动到30。现在您有两个维度,您可以轻松地在10x10矩阵上表示您的问题(每个数字可以有10个不同的值):

matrix representation of the two dimensional problem

在上图中,S是您的来源位置(10),T是您的目标位置(30)。现在您可以应用问题的规则。我不知道你想找到什么:有多少路径?只是一条路?最短的路径?

无论如何,处理动作的算法草图是:

  • 如果你看T你根据问题的规则看到,你可以到达的唯一可能的邻居(30)是(20),(31)和(40) )。

  • 现在,我们假设您选择(20),那么您可以到达的唯一可能的邻居(20)是(21)。

  • 现在,你被迫选择(21),你可以达到的唯一可能的邻居(21)是(11)和(31)。

  • 最后,如果你选择(11),那么你可以达到的唯一可能的邻居(11)是(10)和(12)......和(10)是你的来源{{1} ,所以你已经完成了。

这只是算法的草图(它没有说明如何从可能的邻居列表中进行选择),但我希望它能给你一个想法。

最后,当您解决了二维空间中的问题时,您可以将其扩展到三维空间,并扩展到四维空间(您的原始问题),其中您有一个10x10x10x10矩阵。每个维度始终有10个插槽/位置。

我希望这会有所帮助。

答案 1 :(得分:1)

我想到的第一件事就是这只是一个额外维度的点。也就是说,而不是[x,y]来表示二维网格上的点,你有[w,x,y,z]来表示四维空间中的一个点。

我在你的问题中不确定的一件事是当你将1添加到9时会发生什么。是否有剩余部分被结转,或者这个数字是否被推翻到零?或者这是否代表了无法跨越的边缘?

在任何情况下,我都会将此视为一种具有额外维度的点,并适当地应用您的算法。

答案 2 :(得分:1)

我将从有向图开始,其中每个节点代表您的数字加上额外的自由度(因为约束)。例如。您可以将此视为添加到您的号码中的另一个数字,表示“最后更改的数字”。例如。从1001[0]开始,此节点连接到

1001[0] -> 2001[1]
1001[0] -> 0001[1]
1001[0] -> 1101[2]
1001[0] -> 1011[3]
1001[0] -> 1002[4]
1001[0] -> 0000[4]

2001[1]

2001[1] -> 2101[2]
2001[1] -> 2011[3]
2001[1] -> 2002[4]
2001[1] -> 2000[4]

请注意:????[0]节点仅允许作为起始节点。每条边总是连接不同的最后一位数。

因此,对于每个数字xyzw[d],传出边是由

给出的
xyzw[d] -> (x+1)yzw[1]   if x<9 && d!=1
xyzw[d] -> (x-1)yzw[1]   if x>0 && d!=1
xyzw[d] -> x(y+1)zw[2]   if y<9 && d!=2
xyzw[d] -> x(y-1)zw[2]   if y>0 && d!=2
xyzw[d] -> xy(z+1)w[3]   if z<9 && d!=3
xyzw[d] -> xy(z-1)w[3]   if z>0 && d!=3
xyzw[d] -> xyz(w+1)[4]   if w<9 && d!=4
xyzw[d] -> xyz(w-1)[4]   if w>0 && d!=4

您的目标现在是四个节点1004[1] .. 1004[4]。如果您的算法需要单个目标节点,则可以为每个数字添加一个人工边????[?] -> ????[0],然后将1004[0]作为最终结果。

答案 3 :(得分:1)

你可以将每个状态表示为长度为4的整数数组。然后有一个图形结构来连接状态(我不建议完全构建图形,因为这单独需要O(10 ^ 4)内存)。

然后使用A* algorithm遍历图表并到达目标节点。

或者只是使用BFS遍历例程,在处理状态时生成相邻状态。你必须跟踪已经访问过的状态(某种类似于数据结构的集合)。

答案 4 :(得分:0)

当访问节点时,你需要遍历节点的所有子节点并访问其中的一些节点,所以你应该只实现子生成器函数获取一个参数 - 当前数字如1001.它是算法的“核心”,然后你需要使用recoursion遍历一棵树。以下是不工作的代码,进入无限的再生,但是是一个解释我的想法的草图:

from random import random

def shouldVisit(digits):
    #very smart function defining search strategy
    return random() > 0.5

def traverse(source, target, prev):
    if source == target:
        print 'wow!'
        return
    for i in range(len(source)):
        if i == prev:
            continue
        d = source[i]
        if d > 0:
            res = list(source)
            res[i] = d - 1
            if shouldVisit(res):
                traverse(res, target, i)
        if d < 9:
            res = list(source)
            res[i] = d + 1
            if shouldVisit(res):
                traverse(res, target, i)

def traverse0(source, target):
    def tolist(num):
        digits = []
        while num:
            digits.append(num % 10)
            num /= 10
        return digits
    traverse(tolist(source), tolist(target), -1)

traverse0(1001, 1040)

非常智能的存根函数shouldVisit可以检查例如是否已经访问过给定节点