激活AND节点和OR节点

时间:2017-04-26 18:15:37

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

考虑带有AND节点和OR节点的有向图。 AND节点仅在激活其中的所有边缘时激活。如果OR节点中的至少一个边缘被激活,则激活OR节点。如何设计高效算法来决定是否可以激活所有节点?我考虑过一些天真的算法,但需要O(n ^ 3)时间。我也假设最初激活没有边缘的顶点。我相信n ^ 3不是一个有效的算法,并且有一些我缺少的方法。标记问题可能有解决方案的域。

3 个答案:

答案 0 :(得分:4)

为每个节点维护已激活节点的集合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是边数。

答案 1 :(得分:3)

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

将具有度数为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)

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

完成此过程后,visit包含一组已激活的节点。

答案 2 :(得分:1)

可以在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);
        }
    }
}