如何通过网络中的节点生成随机路径
Posted
技术标签:
【中文标题】如何通过网络中的节点生成随机路径【英文标题】:How to generate a randomized path through nodes in a network 【发布时间】:2016-05-10 09:33:43 【问题描述】:我有一个由 N 个节点连接在一起的常规网络,我想生成一个只访问 n 个节点一次的路径。我还要求路径中存在一定程度的随机性,以便能够在给定相同起始节点的情况下创建不同的路径。
我目前的解决方案是选择一个随机的起始节点,然后随机访问一个相邻的节点,并重复直到我访问 n 个节点。每当路径不允许我访问 n 个节点时,我就会回溯尝试通过另一个节点。
当节点和连接的数量很少时,这可以正常工作,但是当这些数量增加并且 n 接近 N 时,如果有的话,需要很长时间才能找到解决方案.
您能否提出可以保证在合理时间内成功的替代方法?
【问题讨论】:
Prim 的算法和其他旨在找到minimum spanning tree的算法 想要找到“一个解决方案”或“所有”解决方案? @Aravind 一个解决方案就足够了 在您的解决方案中,您还可以在回溯之前尝试路径的另一端。从最初选择的节点继续探索节点,从而使其成为路径上的内部节点。 @Selçuk Cihan,我不确定这是否有助于比回溯更快地找到解决方案。 【参考方案1】:您可以创建一条路径作为分支路径的轮廓,而不是尝试创建一条独特的路径,这会导致您走下许多死胡同。这样的路径将具有相邻的起点和终点。
此图概述了所提出算法的步骤:
首先,将您的网格分成两半 (a)。如果您的某个维度是奇数,请忽略最后一行或最后一列。
现在在粗网格 (b) 上创建一个分支连接的迷宫。有很多算法可以做到这一点; cmets 中提到了 Prim 的算法,但如果您省略回溯,您也可以使用贪婪路径搜索。 Mike Bostock 的Visualizing Algorithms 展示了一些迷宫生成算法;它们位于长页面的底部附近。
接下来,创建迷宫的轮廓。这为您提供了一个简单的路径,如果其维度是偶数 (c),则该路径可以访问原始网格中的所有节点。起点和终点是相邻的;这条路距离封闭仅一步之遥。
如果原始网格的任何尺寸是奇数,您可以随机拉伸一行或一列以覆盖整个网格 (d)。请注意,您必须为每个相交的行或列插入一个新段。否则,一些节点将不会被访问。 (当两个维度都是奇数并且必须调整时,可能会出现问题,因此这是算法的另一个限制:最多一个维度可以是奇数。)
编辑: javascript 中的概念验证实现(无步骤 d)如下。这是一个完整的网页,您可以将其保存为 html 文件并显示在可识别画布元素的浏览器中。
<!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" >Kann nix.</canvas>
</body>
</html>
【讨论】:
【参考方案2】:正如评论的那样,我不确定您是否能比使用无向无权图更快地找到一些东西。
确保您正在实施正确版本的Depth-First(或Breadth-first)搜索算法并添加您对相邻节点的随机选择。
另一种贪婪的解决方案是为每个顶点随机定义一个权重并应用Dijkstra's algorithm。
【讨论】:
以上是关于如何通过网络中的节点生成随机路径的主要内容,如果未能解决你的问题,请参考以下文章