具有多个进入和退出点的广度优先图搜索

时间:2014-01-28 18:35:39

标签: java algorithm graph breadth-first-search adjacency-list

我正在尝试为有向图制作相邻列表,而图表有多个入口和出口点。在图中,节点将是AND,OR,NOT,XOR等,并且入口和出口点将是单个位(0或1)。

我有以下节点:

  • 条目A:1
  • 参赛作品B:1
  • 条目C:0
  • 退出D:?
  • 退出E:?
  • Node1:OR
  • Node2:AND
  • Node3:AND
  • Node4:NOT
  • Node5:AND
  • Node6:OR
  • Node7:NOT
  • Node8:NOT
  • Node9:AND
  • Node10:AND
  • Node11:OR

他们之间有以下联系:

  • 条目A:Node1,Node2
  • 条目B:Node1,Node2
  • 条目C:Node3,Node7,Node10
  • Node1:Node3,Node5
  • Node2:Node4,Node6
  • Node3:Node6
  • Node4:Node5
  • Node5:Node8,Node9
  • Node6:退出D
  • Node7:Node9
  • Node8:Node10
  • Node9:Node11
  • Node10:Node11:
  • Node11:退出E

照片:

Graph of circuit in question

所以现在我需要通过跟随有向图的路径来计算D和E出口处的字节。

我在这里找到了带有单个入口和出口点的呼吸优先图搜索的链接:
Graph Algorithm To Find All Connections Between Two Arbitrary Vertices

如何在链接中调整这个第一次屏幕图搜索,这样我就可以有多个入口和出口点,同时删除/更改递归部分(因为我得到StackOverflowError时使用上面链接中的代码,即使我只有1个进入和退出点)。

3 个答案:

答案 0 :(得分:1)

消除递归的想法如下:当节点的所有连接都获得已知值时,该节点将被排队执行。在您的示例中,在开始时这些是节点N1,N2,N7。 Executor逐个从队列中取出准备执行的节点,计算输出值并将其传递给下一个连接,这可能导致其他节点入队等。当执行队列变空时,结果就绪。

您可以自己编程执行程序和节点(200-300行代码),或者使用现成的库。要搜索库,请查找“有色Petri网java实现”。有许多可用的Petri网引擎的Java实现。除了我自己的df4h-core之外,我没有使用任何一个。从FormulaTest.java开始计算各种数学公式。您必须实现自己的计算布尔运算的节点。

答案 1 :(得分:0)

首先要注意的是,依赖性只沿着每个链接流向一个方向,而你所谓的“节点”则不是。通用图搜索不适合此问题。

如果您发现节点列表和它们之间的链接实际上并未唯一地指定您绘制的图形,则可以轻松确定原因。我可以翻转所有的门,将它们的输出连接到它们的左输入,左输入连接到右边,右边输出,或者反转所有非门的方向,以及你有的节点和链接列表仍然是正确的。

如果我要对此进行建模,我会做一些完全不同的事情:

interface Component {
    boolean value();
}

class And implements Component {
    Component[] inputs;
    public And(Component ... inputs){ this.inputs = inputs; }
    boolean value(){
        for(Component c:inputs) if(!c.value()) return false;
        return true;
    }
}
class Or implements Component {
    Component[] inputs;
    public Or(Component ... inputs){ this.inputs = inputs; }
    boolean value(){
        for(Component c:inputs) if(c.value()) return true;
        return false;
    }
}
class Not implements Component {
    Component input;
    public Not(Component input){ this.input = input; }
    boolean value(){ return !input.value(); }
}
class Input implements Component {
    boolean value;
    public Input(boolean value){ set(value); }
    void set(boolean newValue){ this.value = value; }
    boolean value(){ return value; }
}

现在我们已经拥有了基本的逻辑门,我们可以使用它们构建一个更完整的模型:

public static void main(String ... args){
    Input a = new Input(true), b = new Input(true), c = new Input(false);
    Component n1 = new Or(a, b), n2 = new And(a, b), n3 = new And(c, n2),
              n4 = new Not(n2), n5 = new And(n1, n4), n6 = new Or(n2, n3),
              n7 = new Not(c), n8 = new Not(n5), n9 = new And(n5, n7),
              n10 = new And(c, n8), n11 = new Or(n9, n10);
    Component d = n11, e = n6;
}

结果是d.value()e.value()。如果我们需要将值表示为方程式的字符串,我们可以覆盖每个门的toString方法:

class And implements Component {
    //...
    public String toString(){
        StringBuilder b = new StringBuilder("(");
        for(Component c:inputs) b.append(c).append("&&");
        return b.replace(b.length()-2,b.length,")").toString();
    }
}
class Or implements Component {
    //...
    public String toString(){
        StringBuilder b = new StringBuilder("(");
        for(Component c:inputs) b.append(c).append("||");
        return b.replace(b.length()-2,b.length,")").toString();
    }
}
class Not implements Component {
    //...
    public String toString(){
        return String.format("!%1$s",input);
    }
}

现在,任何Component.toString()都会根据其输入返回其值的逻辑表达式,这些输入本身就是输入的表达式,依此类推,直到原始的Input

答案 2 :(得分:0)

您描述的问题本身并不是图形问题。实际上你需要的是一个布尔表达式求值器。如果将表达式表示为二叉树,则评估很容易。

在你的图片中,D是其中一棵树的根节点。这种树的每个内部节点都有2个子节点,表达式在节点本身。要进行评估,您需要对树进行后序遍历。叶子是A,B,C。为了评估E,只需构建一个不同的树。

如果您需要一些建筑树木的帮助,请告诉我(如果需要,我会尝试添加一些图片)。


在构建表达式树之后,只需尝试叶子的所有可能值:eval(A,B,C)以及所有可能的组合 - eval(false,false,false),eval(false,false,true )等等。

如果你只对一个这样的表达式产生真值的组合感兴趣,那么这是一个已知的NP问题,所以不要指望多项式运行时:Boolean satisfiability problem