给出了大小为n
的图表,并给出了其节点的大小m
的子集。从子集的所有节点中查找distance <=k
的所有节点。
例如。 A-> B-> C-> D-> E是图,subset
= {A,C},k
= 2.
现在,E与C的距离<= 2,但不是来自A,因此不应计算。
我想到从子集中的每个节点运行广度优先搜索,并考虑相应答案的交集 可以进一步优化吗?
我经历了很多关于SO的帖子,但是他们都指向我不理解的kd-trees,还有其他的方式吗?
答案 0 :(得分:2)
我可以想到两个非渐近(我相信)的优化:
当然,如果k很大(接近n),这没有任何帮助,在这种情况下我不知道。但我很肯定k / d树不适用于一般图表:)
答案 1 :(得分:0)
Nicklas B的优化可以应用于以下两种优化。
优化#1:修改BFS以在运行时而不是在后面执行交集。
BFS和交叉路口似乎是要走的路。但是,BFS正在进行减少工作。特别是,它正在扩展它不需要扩展的节点(在第一个BFS之后)。这可以通过将交叉点方面合并到BFS中来解决。
解决方案似乎是保留两组节点,称之为#34; ToVisit&#34; &#34;访问&#34;而不是标记访问过的节点。
BFS的新规则如下:
如果ToVisit集合平均较小,则效果会更好,这往往是m和k远小于N的情况。
优化#2:如果有足够的查询,则预先计算距离,以便查询只进行交叉。 虽然,这与第一次优化不兼容。如果对不同的子集和k值有足够数量的查询,那么最好提前找到每对节点之间的距离,代价是O(VE)。
这种方式只需要进行交叉,即O(V * M * Q),其中Q是查询数,M是查询子集的平均大小,V是节点数。如果预期是O(M * Q)> 0的情况。 O(E),那么这种方法应该少工作。注意两个最远的节点是有用的,因为任何等于或大于等的k将始终返回所有顶点的集合,在这种情况下导致查询成本仅为O(V)。
然后应以四种形式存储距离数据。
第一个是&#34; kCount [A] [k] =距离A&#34;距离为k或更小的节点数。这提供了Niklas B的替代方案。建议&#34;从距离最大的子集中的两个节点开始,以获得最小的剩余图表&#34;在O(m)>的情况下, O(sqrt(V))因为找到最小值是O(m ^ 2)并且最好避免试图找到起始对的最佳选择并且选择一个好的选择。您可以从子集中的两个节点开始,该数据结构中给定k的值最小。您也可以按此指标对子集中的节点进行排序,并按此顺序执行交叉。
第二个是&#34; kMax [A] = A&#34;的最大k,可以使用散列图/字典来完成。如果k> =该值,那么除非kCount [A] [kMax [A]] <1,否则可以跳过该值。 (顶点数),意味着并非所有节点都可以从A到达。
第三个是&#34; kFrom [A] [k] =节点k与A&#34;的距离,因为k从0到最大距离有效,一个散列图/字典到一个数组/ list可以在这里使用,而不是嵌套的hashmap / dictionary。这样可以节省空间和时间***创建距离为&lt; = k的节点集。
第四个是&#34; dist [A] [B] =从A到B&#34;的距离,这可以使用嵌套的hashmap / dictionary来完成。这允许相当快速地处理交叉检查。
* 如果空间不是问题,那么这个结构可以存储距离A的所有节点k或更小的距离,但这需要O(V ^ 3)空间,因此需要时间。然而,主要的好处是它还允许存储大于k距离的单独节点列表。这允许算法使用较小的集合,dist&gt; k或dist&lt; = k。在dist&lt; = k的情况下使用交叉点并在dist&lt; = k或交叉点的情况下设置减法,然后在主集具有最小化尺寸的情况下设置减法。
答案 2 :(得分:0)
s
)并将其连接到所有m
个给定节点。 s
中找到距离小于或等于k + 1的所有节点,并从中减去m。 T(n)=O(V+E)