如何通过网络中的节点生成随机路径

时间:2016-02-01 19:40:59

标签: algorithm math computer-science

我有一个连接在一起的 N 节点的常规网络,我想生成一个只访问 n 节点的路径。我还要求路径中存在一定程度的随机性,这样我就可以在给定相同起始节点的情况下创建不同的路径。

See the problem illustration here.

我目前的解决方案是选择一个随机起始节点,然后随机访问一个相邻节点,然后重复,直到我访问 n 节点。每当路径不允许我访问 n 节点时,我就会回溯以尝试通过另一个节点。

当节点数和连接数很小时,这种方法很好,但是当这些数据增加并且 n 接近 N 时,如果有的话,需要很长时间才能找到解决方案

你能否建议在合理的时间内保证成功的替代方法?

2 个答案:

答案 0 :(得分:3)

您可以创建单个路径作为分支路径的轮廓,而不是尝试创建一个独特的路径,这将导致您走向许多死角。这些路径将具有相邻的起点和终点。

该图概述了所提算法的步骤:

Four steps of the proposed algorithm

首先,将你的网格分成两半(a)。如果您的某个维度为奇数,请忽略最后一行或列。

现在在粗网格上创建一个分支连接的迷宫(b)。有很多算法;注释中提到了Prim的算法,但如果省略回溯,也可以使用贪心路径搜索。 Mike Bostock的Visualizing Algorithms展示了一些迷宫生成算法;它们靠近长页的底部。

接下来,创建该迷宫的轮廓。这为您提供了一个简单的路径,如果其尺寸为偶数(c),则访问原始网格中的所有节点。起点和终点相邻;这条路只是关闭的一步。

如果原始网格的任何尺寸都是奇数,则可以拉伸随机行或列以覆盖整个网格(d)。请注意,您必须为每个交叉行或列插入新段。否则,将不会访问某些节点。 (当两个维度都是奇数并且必须进行调整时可能存在问题,因此算法的另一个限制是:最多一个维度可能是奇数。)

编辑:Javascript中的概念验证实现(没有步骤d)如下所示。它是一个完整的网页,您可以将其保存为html文件并显示在识别canvas元素的浏览器中。

<!DOCTYPE html>

<html>

<head>
<meta charset="utf-8" />
<title>Simple Path Demo</title>
<script type="text/javascript">

    function array2d(w, h, val) {
        var arr = [];

        for (var y = 0; y < h; y++) {
            var row = [];

            for (var x = 0; x < w; x++) row.push(val);
            arr.push(row);
        }

        return arr;
    }

    var dir = {
        n: {x: 0, y: -1},
        e: {x: 1, y: 0},
        s: {x: 0, y: 1},
        w: {x: -1, y: 0},
    };

    var width = 72;
    var height = 72;

    var node = array2d(width, height, false);



    function walk(x, y, from) {
        if (x < 0 || x >= width / 2) return;
        if (y < 0 || y >= height / 2) return;

        if (node[2*y][2*x]) return;

        node[2*y][2*x] = true;          

        if (from == 'n') node[2*y + 1][2*x] = true;
        if (from == 'e') node[2*y][2*x - 1] = true;
        if (from == 's') node[2*y - 1][2*x] = true;
        if (from == 'w') node[2*y][2*x + 1] = true;

        var d = ['n', 'e', 's', 'w'];

        while (d.length) {
            var pick = (Math.random() * d.length) | 0;
            var head = d[pick];
            var next = dir[head];

            d[pick] = d[d.length - 1];
            d.pop();

            walk(x + next.x, y + next.y, head);
        }        
    }

    function cell(x, y) {
        if (y < 0 || y >= height) return false;
        if (x < 0 || x >= width) return false;

        return node[y][x];
    }

    function path(x, y) {
        var x0 = x;
        var y0 = y;

        var res = "";
        var dir = "s";

        var l, r;

        y++;

        while (x != x0 || y != y0) {
            var old = dir;

            res += dir;

            switch (dir) {
            case "n":   l = (cell(x - 1, y - 1)) ? 1 : 0;
                        r = (cell(x, y - 1)) ? 2 : 0;
                        dir = ["w", "n", "e", "e"][l + r];
                        break;

            case "e":   l = (cell(x, y - 1)) ? 1 : 0;
                        r = (cell(x, y)) ? 2 : 0;
                        dir = ["n", "e", "s", "s"][l + r];
                        break;

            case "s":   l = (cell(x, y)) ? 1 : 0;
                        r = (cell(x - 1, y)) ? 2 : 0;
                        dir = ["e", "s", "w", "w"][l + r];
                        break;

            case "w":   l = (cell(x - 1, y)) ? 1 : 0;
                        r = (cell(x - 1, y - 1)) ? 2 : 0;
                        dir = ["s", "w", "n", "n"][l + r];
                        break;
            }

            if (dir == "n") y--;
            if (dir == "e") x++;
            if (dir == "s") y++;
            if (dir == "w") x--;
        }

        return res;
    }

    walk(0, 0);
    var p = path(0, 0);

    window.onload = function() {
        var cv = document.getElementById("map");
        var cx = cv.getContext("2d");
        var s = 8;

        cx.translate(2*s, 2*s);
        cx.lineWidth = 2;

        var x = 0;
        var y = 0;

        cx.beginPath();
        cx.moveTo(s*x, s*y);

        for (var i = 0; i < p.length; i++) {
            var c = p.charAt(i);

            x += dir[c].x;
            y += dir[c].y;

            cx.lineTo(s*x, s*y);
        }

        cx.stroke();
    }

</script>
</head>

<body>
<canvas id="map" width="608" height="608">Kann nix.</canvas>
</body>

</html>

答案 1 :(得分:0)

如评论所述,我不确定您是否能找到比使用未定向的未加权图表更快的内容。

确保您正在实施Depth-First(或Breadth-first)搜索算法的正确版本,并添加随机选择的相邻节点。

另一个但是贪婪的解决方案是随机定义每个顶点的权重并应用Dijkstra's algorithm