在我的特定情况下,图表被表示为邻接列表,并且是无向和稀疏的,n可以是数百万,d是3.计算A ^ d(其中A是邻接矩阵)并挑选出非零条目有效,但我想要一些不涉及矩阵乘法的东西。对每个顶点进行广度优先搜索也是一种选择,但速度很慢。
答案 0 :(得分:1)
def find_d(graph, start, st, d=0):
if d == 0:
st.add(start)
else:
st.add(start)
for edge in graph[start]:
find_d(graph, edge, st, d-1)
return st
graph = { 1 : [2, 3],
2 : [1, 4, 5, 6],
3 : [1, 4],
4 : [2, 3, 5],
5 : [2, 4, 6],
6 : [2, 5]
}
print find_d(graph, 1, set(), 2)
答案 1 :(得分:0)
假设我们有一个函数verticesWithin(d,x)
,可以找到顶点d
距离x
内的所有顶点。
这个问题的一个好策略是揭示缓存/记忆机会,就是问一个问题:这个问题的子问题如何相互关联?
在这种情况下,我们可以看到verticesWithin(d,x)
d >= 1
vertices(d-1,y[i])
是范围内所有i
y=verticesWithin(1,x)
的联合,d == 0
。如果{x}
则只是d == 1
。 (我假设一个顶点被认为与自身的距离为0。)
实际上,您需要查看案例x
的邻接列表,而不是使用该关系,以避免无限循环。您还希望避免将y
本身视为verticesWithin(d,x)
成员的冗余。
此外,如果d
的返回类型从简单列表或集合更改为x
集合列表,表示距verticesWithin(d,x) = init(verticesWithin(d+1,x))
的距离越来越远,则
init
其中verticesWithin
是产生列表中除最后一个元素之外的所有元素的函数。显然,如果将字面转换为代码,这将是一个非终止的递归关系,所以你必须对你如何实现它有点聪明。
配备子问题之间的这些关系,我们现在可以缓存{{1}}的结果,并使用这些缓存的结果来避免执行冗余遍历(虽然以执行某些设置操作为代价 - 我并非完全确定这是一场胜利)。我将把它作为练习来填写实施细节。
答案 2 :(得分:0)
您已经提到了计算A^d
的选项,但这远远超出您的需要(正如您已经说过的那样)。
v
,表示一组顶点。向量w := A v
现在在每个节点都有一个,只需一步即可从起始节点到达。迭代,u := A w
对于您可以在两个步骤中从起始节点到达的每个节点都有一个,等等。
对于d=3
,您可以执行以下操作(MATLAB伪代码):
v = j'th unit vector
w = v
for i = (1:d)
v = A*v
w = w + v
end
向量w
现在每个节点都有一个肯定条目,可以在j
个步骤中从d
节点访问。
答案 3 :(得分:0)
在这种情况下,从给定顶点开始的广度优先搜索是最佳解决方案。你会发现距离d内的所有顶点,你甚至都不会访问任何距离为> = d + 2的顶点。
这是递归代码,尽管通过使用队列可以很容易地完成递归。
// Returns a Set
Set<Node> getNodesWithinDist(Node x, int d)
{
Set<Node> s = new HashSet<Node>(); // our return value
if (d == 0) {
s.add(x);
} else {
for (Node y: adjList(x)) {
s.addAll(getNodesWithinDist(y,d-1);
}
}
return s;
}