当前位置: 首页 > 知识库问答 >
问题:

有向无环图的有效遍历

令狐俊风
2023-03-14

输入:

nd[0];
nd[1, 2];
nd[3, 4];
nd[0, 1];
nd[2, 3];
nd[0, 4];
nd[1, 3];
nd[0, 2];
nd[1, 4];
nd[3];
nd[1, 4];

生成的树:

输出:

total_time = sum of all individual wait_time //without overlap

规则:

    < li >输入代码总是会产生一个有向无环图 < li >每个节点都有一些wait_time值 < li >完整的图形遍历应该计算整个图形的总等待时间 < li >必须并行遍历所有独立节点(或者至少时间计算应该是这样) < li >如果两个不同节点的wait_time发生重叠,则将考虑最大值,遍历时间较短的节点将移动到下一个独立节点 < li >除了根和叶(可以有多个根和叶)之外,所有单个和成对的节点将正好有1条和2条入边和出边

问题1:如何将给定的输入代码转换为图形,以便可以遍历?(伪代码或任何类型的指导可能会有所帮助)

问题2:如何根据上述规则实现成功的遍历?

以前的努力:

>

  • 我能够使用拓扑排序以线性方式对节点进行排序,但我不确定如何实现这些特定目标。

    我根据代码的直觉绘制了这个图。

    边缘的数字只是为了澄清导致依赖的数字。

    我正在使用python 3

    我之前的代码似乎与这些问题没有任何意义,所以我没有包含它。

  • 共有1个答案

    胥博文
    2023-03-14
    1. 创建图形

    a、b、c 三个节点,它们具有 0 属性/共同的解除性(到节点 0)。如果 ab 之前发现,而 bc 之前发现,则边应为 a-

    要解决上述规则,请考虑为每个发现的数字设置缓存。如果一个节点包含0,那么您将其缓存为缓存[0]。稍后,如果其他节点b包含0,您必须从缓存[0]b创建边缘,并更新该缓存,以便包括0的后续节点从b获得边缘。

    foreach input as node
      forall dependancy of node
        if discovered[dependancy]
          make_edge(discovered[dependancy], node)
        fi
        discovered[dependancy] = node // apply dependancy "transitivity"
    

    现在,要将图形构建为“层”,您可以从叶子开始(层<代码>0 [1,4]。(因为<code>[1,3]在链接到<code>[3]时,它是一个叶子,也链接到<code>[1,4]而不是。因此排除在外)。然后,您构建了层<code>1</code>。

    构建第n层时,您只能将具有dep的节点添加到第0层到第n-1层

    一种更简洁的说法是对一个节点来说,计算它的偏心度(最长的路径(这里到树叶))。

    要像您一样打印图形,请注意,您可以通过偏心度绘制节点,这将显示依赖的“级别”(它们距离叶子/末端有多远,请参阅下面代码中的plotByLayers)。

    我们不需要像上面那样麻烦地构建层。

    节点只能在其所有祖先结束时启动。

    祖先在我们做图的时候就已经确定了。

    因此,递归是

    n.endAt = max(n.endAt for n in n.ancestors) + n.wait
    

    初始化是针对根节点(没有依赖关系)的,我们可以在其中保留等待时间。

    nroot.endAt = nroot.wait
    

    关于节点。id表示法<code>i)x,y。i是作为读入输入的第i个节点。(不知何故,它的真实id。x,y只是帮助我们可视化的垃圾。)。

    const input = `
    nd[0];
    nd[1, 2];
    nd[3, 4];
    nd[0, 1];
    nd[2, 3];
    nd[0, 4];
    nd[1, 3];
    nd[0, 2];
    nd[1, 4];
    nd[3];
    nd[1, 4];`
    function makeGraph(input) {
      const nodes = input.trim().split('\n').map((x,i) => {
        const deps = x.match(/\[(.+)\]/)[1]
        return { id: i+')'+deps, v: deps.split(',').map(x => x.trim()) }
      })
      const edges = {}
      const discovered = {}
      nodes.forEach((node, i) => {
        node.v.forEach(digit => {
          if (discovered[digit]) {
            // there is an edge
            edges[discovered[digit].id] = edges[discovered[digit].id] || []
            edges[discovered[digit].id].push(node)
          }
          // apply transitivity a->b->c
          discovered[digit] = node
        })
      }) 
      return {nodes, edges}
    }
    
    function computeEccentricity(n, edges) {
      if (typeof(n.eccentricity) !== 'undefined') {
        return n.eccentricity
      }
      if (!edges[n.id]) {// a leaf has no outgoing edges
        n.eccentricity = 0
        return 0
      }
      const distances = Object.values(edges[n.id]).map(n => computeEccentricity(n, edges))
      const min = Math.max(...distances)
      n.eccentricity = 1 + min
      return n.eccentricity
    }
    
    function plotByLayers(nodes) {
      const lvls = []
      let m = 0;
      nodes.forEach(n => {
        const i = n.eccentricity
        lvls[i] = lvls[i] || []
        lvls[i].push(n)
        m = i > m ? i: m
      })
      for(let i = m; i >=0 ; --i) {
        console.log(lvls[i].map(x => x.id))
      }
      return lvls
    }
    const { nodes, edges } = makeGraph(input)
    nodes.forEach(n => computeEccentricity(n, edges))
    plotByLayers(nodes)
    
    // for any node, compute its ancestors.
    nodes.forEach((n, i) => {
      if (edges[n.id]) {
        edges[n.id].forEach(v => {
          v.ancestors = v.ancestors || []
          v.ancestors.push(n)
        })
      }
      n.wait = 2**i // say arbitrarily that i node waits 2^i some time
    })
    function computeEndAt(node) {
      if (typeof(node.endAt) !== 'undefined') {
        return node.endAt
      }
      if (!node.ancestors) {
        node.endAt = 0 + node.wait
        return node.endAt
      }
      const maxEnd = Math.max(...node.ancestors.map(computeEndAt))
      node.endAt = maxEnd + node.wait
      return node.endAt
    }
    nodes.forEach(computeEndAt)
    const longest = nodes.sort((a,b)=>b.endAt - a.endAt)[0]
    console.log('awaited: ', longest.endAt, longest.id)
     类似资料:
    • 有效的解决方案路由的约束是: 考虑到第二个约束,路由中遍历的所有边的权重之和必须是图中可能的最高值。 所选路由中必须访问过N个顶点(包括起始和结束顶点)。 通常,图形将有大量的顶点和边,所以尝试所有的可能性是不可能的,需要相当有效的算法。

    • 在图论中,如果一个有向图从任意顶点出发无法经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。 因为有向图中一个点经过两种路线到达另一个点未必形成环,因此有向无环图未必能转化成树,但任何有向树均为有向无环图。 一、简介 有向无环图是图论的重要概念,我们将首先介绍图的概念和定义,随后介绍有向图,再逐渐引至有向无环图(DAG)。值得一提的是,当DAG用于指代模型时一般指向贝叶斯网络。 一个图G

    • 我正在努力寻找一个时间复杂度为o(m log n)+o(n)的问题的解决方案。 假设有向无环图有n个节点和m个请求,每个节点最多有一个父节点。在时间=0时,图为空。请求有两种类型:添加边(u,v)或查找顶点为u的子图的根。只有在不破坏图的任何属性的情况下才应该添加边(它应该保持无循环,每个节点最多仍然应该有一条传入边)。 这样,检查添加edge是否破坏属性或返回root需要O(1)个时间。然而,更

    • 考虑以下无向非循环图: 如果我们定义“根”为A和E,有没有算法可以确定产生的有向无环图?: 我考虑过从根开始尝试某种DFS或BFS,但我不确定如何处理“等待”的需要,以查看另一个根是否可能到达给定的节点。

    • 我正在寻找一种更有效的方法来修剪用JGrapht构造的有向无环图(a DAG)。 DAG表示一组网络会话之间的时间关系。会话的父会话是在子会话开始之前完成的任何会话。构建DAG相对简单,但存在大量不必要的关系。为了提高效率,我希望对DAG进行修剪,以便每个子级与最小的父级数量有直接关系(或者相反,以便每个父级具有最小的直接子级数量)。 我现在使用的剪枝实现(如下所示)是基于在Streme中找到的代

    • 如何将有向无环图转换为哈希值,以便任何两个同构图哈希到相同的值?两个同构图哈希到不同的值是可以接受的,但不可取的,这就是我在下面的代码中所做的。我们可以假设图中的顶点数最多为11个。 我对Python代码特别感兴趣。 这是我所做的。如果 是从节点到后代(不是子节点!)的映射,那么我根据修改后的拓扑排序重新标记节点(如果可以的话,它更喜欢先对具有更多后代的元素进行排序)。然后,我对排序的字典进行哈希