algorithm - 如何在有向图中找到彼此距离 k 的所有节点(探索图中的每条边)?

标签 algorithm graph depth-first-search breadth-first-search

0

我正在解决一个问题,我需要找到彼此距离为 k 的所有节点。因此,如果 k=3,那么我需要找到它们通过距离 3 的路径连接的所有节点。没有自边,所以如果 i 有一条边指向 s,s 不能直接指向回 i。我想我在这里想到了两个实现,都涉及 BFS。我注意到 BFS 可能不会访问所有边缘的边缘情况,因为节点可能已经被访问过。

在每个节点做BFS。跟踪某个数组中每个节点的“级别”,其中 distance[0] 是根节点,distance1 是与根节点相邻的所有节点,distance[2] 是根节点的所有孙节点等在。然后为了找到距离 k 处的所有节点,我们查看 distance[i] 和 distance[i+k]。

做一次BFS,使用与上面相同的距离算法,但不要在每个节点都做BFS。反转所有边并再次执行 BFS 以查找任何遗漏的路径。这将比方法 1 具有更好的时间复杂度,但我不确定它是否真的会探索每条边和路径(在我的测试用例中它似乎是)。

有更好的方法吗?作为此图中 k = 2 的示例:

enter image description here

路径为 1 到 3、1 到 5、2 到 6、2 到 5、4 到 3、1 到 4。

编辑:边的反转不起作用,我目前最好的选择是先做一个 BFS,然后在每个节点做一个 DFS,直到达到深度 k。

最佳答案

您可以考虑一个基本的相邻矩阵 M,其中的元素不是 01 以指示连接,而是它们保存大小为 k 的可用路径。

例如 对于 2->5,您将存储 M(2,5) = {1,2}(因为在节点 2 和 5 之间存在长度为 1 和长度为 2 的路径)

abM 的两个元素

a * b 定义为:

ab_res = {} //a set without duplicates
for all size i in a
    for all size j in b
        s = i+j
        append(s) to ab_res
ab_res;

a + b 定义为:

ab_res = {}
for all size i in a
    append(i) to ab_res
for all size j in a
    append(j) to ab_res

这种方法不允许重新计算劣质路径。它也适用于循环。

下面是一个未优化的版本来说明算法。

const pathk = 2;
let G = {
    1:[2],
    2:[3,4,5],
    4:[6],
    6:[3]
}
//init M
let M = Array(6).fill(0).map(x=>Array(6).fill(0).map(y=>new Set));
Object.keys(G).forEach(m=>{
    G[m].forEach(to=>{
        M[m-1][to-1] = new Set([1]);
    })
});


function add(sums){
    let arr = sums.flatMap(s=>[...s]);
    return new Set(arr);
}
function times(a,b){
    let s = new Set;
    [...a].forEach(i=>{
        [...b].forEach(j=>{
            s.add(i+j);
        })
    });
    return s;
}
function prod(a,b, pathk){
    //the GOOD OL ugly matrix product :)
    const n = a.length;
    let M = Array(6).fill(0).map(x=>Array(6).fill(0).map(y=>new Set));
    a.forEach((row,i)=>{
        for(let bcol = 0; bcol<n; ++bcol){

            let sum = [];
            for(let k = 0; k<n; ++k){
                sum.push( times(a[i][k], b[k][bcol]) );
            }
            M[i][bcol] = add(sum);
            if(M[i][bcol].has(pathk)){
                console.log('got it ', i+1, bcol+1);
            }
        }
    })
    return M;
}

//note that
//1. you can do exponentiation to fasten stuff
//2. you can discard elems in the set if they equal k (or more...)
//3. you may consider operating the product on an adjency list to save computation time & memory..
let Mi = M.map(r=>r.map(x=>new Set([...x])));//copy
for(let i = 1; i<=pathk; ++i){
    Mi = prod(Mi,M, pathk);
}

关于algorithm - 如何在有向图中找到彼此距离 k 的所有节点(探索图中的每条边)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58533929/

相关文章:

c - 在图中使用队列进行拓扑排序

algorithm - 从二进制卷中分离对象

c++ - 如何有效地处理单个时间线上传入的延迟事件?

algorithm - 随机访问固定字母表中 3 个符号的排序集合的枚举

algorithm - 如何构建连接组件图?

java - 如何在有向图上实现深度优先搜索访问所有顶点

c# - 跟踪数组元素顺序

android-我需要设计 180 度图(半饼图)

csv - neo4j:mac 上的文件路径(导入 csv 文件)

prolog 深度优先迭代深化