【问题标题】:Activating AND nodes and OR nodes激活 AND 节点和 OR 节点
【发布时间】:2017-09-24 07:08:40
【问题描述】:

考虑具有 AND 节点和 OR 节点的有向图。仅当激活其中的所有 in 边时,才激活 AND 节点。如果激活其中的至少一条 in 边,则激活 OR 节点。如何设计一个高效的算法来决定是否所有的节点都可以被激活?我想到了一些简单的算法,但它需要 O(n^3) 时间。我还假设最初激活了没有边缘的顶点。我相信 n^3 不是一种有效的算法,并且我缺少一些方法。标记问题可能有解决方案的域。

【问题讨论】:

  • 所有没有传入边的节点最初都被激活,然后你通过图传播它并想知道是否所有节点都被激活了?
  • 是的,一个不太幼稚的算法..
  • 这不是数字逻辑电路。它是一个图表。如果问题令人困惑,我很抱歉。我没有提到任何与数字逻辑电路相关的标签。
  • 彼得的回答更好——我认为你应该接受这个,而不是我的。
  • 我一定是遗漏了什么,因为似乎答案总是“是”——因为怎么可能连一个节点都没有被激活?

标签: algorithm time-complexity workflow graph-algorithm computation-theory


【解决方案1】:

您可以预处理图形以计算每个节点的入度。

将所有入度为 0 的节点添加到堆栈中,并准备一个数组 A,其中包含每个节点的激活计数(初始等于 0)。

然后做下面的伪代码

visited = set(stack)
while stack:
   node = stack.pop()
   for dest in node.neighbours():
      A[dest] += 1
      if ((Type[dest]==AND and A[dest]==indegree[dest]) or
          (Type[dest]==OR and A[dest]>0)):
         if node not in visited:
            visited.add(node)
            stack.append(dest)

这将最多访问每个边和每个节点一次,因此将具有线性复杂度。

当你完成这个过程时,visited 包含一组激活的节点。

【讨论】:

  • 我认为这与我的代码基本相同,只是更优雅:)
  • 感谢您的客气话:我想这是一个视角问题 - 您的解决方案对我来说看起来更好:)
【解决方案2】:

维护一组A的已激活节点,一个队列Q的节点,以及每个节点的入边计数器C

从计算边数开始:

for each n in nodes {
    for each n2 adjacent to n {
        C[n2] += 1
    }
}

然后用没有入边的节点初始化 Q:

for each n in nodes {
    if C[n] == 0 {
        add n to Q
    }
}

现在重复这个过程,直到队列为空:

take q from Q
for each n adjacent to q {
   if n is in A { continue }
   if n is OR {
      add n to A
      add n to Q
   } else { // n must be AND
      C[n] -= 1
      if C[n] is 0 {
          add n to A
          add n to Q
      }
   }
}

[这是拓扑排序的一种变体,用于处理 OR 和 AND 节点之间的差异]。

当此进程终止时,集合A 包含所有激活的节点。

运行时间为 O(V+E),其中 V 是图中的节点数,E 是边数。

【讨论】:

    【解决方案3】:

    在 O(n) 中是可能的。这是一个可能的算法。

    n总节点数

    s已激活节点的总和

    a 数组表示节点 n 是否已被激活

    c 数组来计算节点 n 的传入边数

    遍历节点,如果它们没有传入的边调用你的传播函数,例如propagate(i);.

    如果s == n所有节点都已激活。

    propagate 函数的伪代码:

    function propagate(idx) {
        if (a[idx]) // is node activated already
            return; // return because node was already propagated
        a[idx] = true; // activate
        s++; // increase the number of activated nodes
        for (var j = 0; j < outEdges[idx].length; j++) { // iterate through the outgoing edges
            var idx2 = outEdges[idx][j]; // the node the edge is pointing to
            if (isOrNode[idx2]) {
                propagate(idx2);
            } else { // AND node
                c[idx2]++; // increase the count of incoming activated edges
                if (inEdges[idx2].length == c[idx2]) // all incoming edges have been activated
                    propagate(idx2);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-03-27
      • 2018-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多