在六边形网格中找到n长度的所有可能路径

时间:2016-02-02 10:07:58

标签: algorithm recursion graph-algorithm depth-first-search

假设函数将s(原点六边形),f(目标六边形)和n(路径长度)值作为参数并输出所有可能路径的列表有n长度。要想象出问题,请查看下图:

enter image description here

让我们说我们的起源(s)是红色虚线十六进制(2, 3),目标(f)是蓝色虚线(5, 2)。我们希望以5个步骤(n = 5)到达蓝色虚线十六进制。还要考虑如果步行到达特定的十六进制,它也可能在下一步中保留在该十六进制中。换句话说,其中一条可能的路径可以是(3, 2) - (4, 2) - (5, 2) - (5, 2) - (5, 2)。它也算作5长度路径。

这些是从(2, 3)(5, 2)的一些示例路径:

(1, 3) - (2, 3) - (3, 2) - (4, 3) - (5, 2)
(3, 3) - (4, 4) - (5, 4) - (5, 3) - (5, 2)
(2, 3) - (2, 3) - (3, 3) - (4, 3) - (5, 2)

我希望以某种方式找到所有这些路径。但是,我无法确定哪种算法能够提供最有效的解决方案来解决此问题。首先想到的是使用深度优先搜索,但我想知道在这种情况下是否有更好的选择。

2 个答案:

答案 0 :(得分:1)

假设您定义了以下递归函数,返回对列表的列表,其中每个对列表是从fromto的长度为i的路径:

find_paths_from_to_with_length(from, to, i):
    if i == 1:
        if to in neighbors(from) or from == to:
            return [[(from, to)]]
        return []

    all_paths = []
    for node in neighbors(from) + [from]:
        neighbor_all_paths = find_paths_from_to_with_length(node, to, i - 1)
        for path in neigbor_all_paths:
            all_paths.append([(from, node)] + neighbor_path

    return all_paths

然后你只需要用你的来源,目标和所需的长度来调用它。

答案 1 :(得分:1)

对于像这样的十六进制网格,

enter image description here

两个节点之间的曼哈顿距离可以通过使用:

来计算
function dist = manhattan_dist( p, q )

    y1 = p(1);
    y2 = q(1);
    x1 = p(2);
    x2 = q(2);

    du = x2 - x1;
    dv = (y2 - floor(x2 / 2)) - (y1 - floor(x1 / 2));

    if ((du >= 0 && dv >= 0) || (du < 0 && dv < 0))
        dist = abs(du) + abs(dv);

    else
        dist = max(abs(du), abs(dv));
    end

end

以前在这些问题中已经讨论过这个问题:

我相信我们可以通过将其与manhattan_dist

相结合来增强Ami的答案
function all_paths = find_paths( from, to, i )

    if i == 1
        all_paths = to;
        return;
    end

    all_paths = [];
    neighbors = neighbor_nodes(from, 8);
    for j = 1:length(neighbors)
        if manhattan_dist(neighbors(j,:), to) <= i - 1
            paths = find_paths(neighbors(j,:), to, i - 1);
            for k = 1:size(paths, 1)
                all_paths = [all_paths; {neighbors(j,:)} paths(k,:)];
            end
        end
    end

end

最后,如您所见,有一个辅助函数来获取邻居节点的索引:

function neighbors = neighbor_nodes( node, n )

    y = node(1);
    x = node(2);

    neighbors = [];
    neighbors = [neighbors; [y, x]];

    if mod(x,2) == 1
        neighbors = [neighbors; [y, x-1]];

        if y > 0
            neighbors = [neighbors; [y-1, x]];
        end

        if x < n - 1
            neighbors = [neighbors; [y, x+1]];
            neighbors = [neighbors; [y+1, x+1]];
        end

        neighbors = [neighbors; [y+1, x-1]];

        if y < n - 1
            neighbors = [neighbors; [y+1, x]];
        end

    else
        if y > 0
            neighbors = [neighbors; [y-1, x]];
            neighbors = [neighbors; [y-1, x+1]];
            if x > 0
                neighbors = [neighbors; [y-1, x-1]];
            end
        end

        if y < n
            neighbors = [neighbors; [y+1, x]];
            neighbors = [neighbors; [y, x+1]];    

            if x > 0
                neighbors = [neighbors; [y, x-1]];
            end
        end
    end

end

如果节点与目标节点的曼哈顿距离大于当前递归调用的长度n,则主要思想就是修剪节点。举例来说,如果我们可以分两步((1, 1))从(0, 3)转到n = 2,则应修剪除(1, 2)以外的所有邻居节点。