Source& Source中的有向图中的所有非循环路径。目的地使用记忆

时间:2013-07-08 15:15:22

标签: java algorithm optimization recursion graph-theory

我正在研究一个研究问题,该问题涉及在一般有向图中存储从源顶点到目标顶点的所有非循环路径(可能是也可能不是循环的)。输入包括有向图,源顶点和目标顶点。

我在Java中编写了一个方法来执行此操作。我已经使用了memoization的概念,通过存储从源顶点到目的地的所有非循环路径,这样如果我在方法的递归调用期间到达相同的顶点,我可以使用存储的'Routes',并且节省了大量的计算费用。

我在算法的递归步骤(我认为)中出错了,我花了一些时间思考可能是什么错误,但我无法找到它。我很感激这方面的任何帮助。提前谢谢!

哦,如果有人想要了解任何代码块的目的,请发表评论!

我基本上在我的方法中使用DFS来解决问题。我的代码如下:

//'allEdges' is an ArrayList of all edges of the input graph

/*'Route' is a class that stores the 'src', 'dest' and 'edgeIndices' of 'allEdges'
that comprise the route from 'src' to 'dest'*/

/*'hashMap' is a HashMap<Integer, ArrayList<Route>>. It maps an integer source vertex
 to a list of all routes from that vertex to the actual destination vertex to which
the method is initialized from main()*/


static void findPaths(int source, int dest)
{
    int i,j,k;
    for(i=0;i<allEdges.size();i++)
    {
        if(allEdges.get(i).getStartNode()==source)
        {
            ArrayList stack = new ArrayList();
            stack.add(i);   //pushing edge index to stack
            if(allEdges.get(i).getEndNode()==dest)
            {
                ArrayList<Route> list1 = hashMap.get(source);   

                if(list1!=null)
                {
                    list1.add(new Route(source,dest,stack));
                    hashMap.put(source, list1);
                }
                else
                {
                    ArrayList<Route> list2 = new ArrayList();
                    list2.add(new Route(source,dest,stack));
                    hashMap.put(source, list2);
                }

            }
            else
            {
                int nextNode = allEdges.get(i).getEndNode();
                ArrayList<Route> temp = hashMap.get(nextNode);
                if(temp!=null)
                {
    for1:           for(j=0;j<temp.size();j++)
                    {
                        ArrayList path = temp.get(j).getEdgeIndices();

                        for(k=0;k<path.size();k++)
                        {
                            int edgeIndex = (int)path.get(k);
                            Edge ed = allEdges.get(edgeIndex);
                            if(ed.getStartNode()==source)
                            {
                                continue for1;
                            }
                        }

                        stack.addAll(path);

                        ArrayList<Route> list3 = hashMap.get(source);
                        if(list3!=null)
                        {
                            list3.add(new Route(source,dest,stack));
                            hashMap.put(source,list3);
                        }
                        else
                        {
                            ArrayList<Route> list4 = new ArrayList();
                            list4.add(new Route(source,dest,stack));
                            hashMap.put(source,list4);
                        }


                        stack.removeAll(path);
                    }
                }
                else
                {
                    findPaths(nextNode, dest);
                }
            }    
        } 
    }

}

编辑1:

对于以下输入图:

顶点数= 5

Source Vertex = 1

目的地顶点= 5

定向边:1 - &gt; 2,1 - > 3,1-&gt; 4,2-&gt; 4,4 - &gt; 5

从1到5的所有路径都是:

1 - &gt; 2 - &gt; 4 - &gt; 5

1 - &gt; 4 - &gt; 5

调用findPaths(1,5)时的输出'hashMap'如下:

对于顶点'1','hashMap'只存储一个'Route',并且该路径只有一个'Edge':1 - &gt; 4

对于顶点'2','hashMap'没有存储'Route',即它映射到'null'。

对于顶点'3','hashMap'没有存储'Route',即它映射到'null'。

对于顶点'4','hashMap'只存储一个'Route',并且该路径只有一个'Edge':4 - &gt; 5

对于顶点'5','hashMap'没有'Route'存储,即它映射到'null'。

显然,'hashMap'存储错误的'Route'。

编辑2:

好的,所以在进行了Brainstorm建议的修改后,该程序适用于非循环图。我希望它也适用于循环图。我试了几个 输入和有趣的是,我注意到,通过Brainstorm建议的修改,如果循环边缘属于ArrayList 'allEdges'的末尾,则程序适用于某些循环图。换句话说,边缘在输入中出现的顺序产生差异,这是不理想的。

现在,我意识到我忘记在递归中标记当前“正在处理”的节点,因此代码卡在无限递归调用序列中。所以我所做的是创建一个全局堆栈inProcess,它将包含在其中一个递归调用中充当source的节点,以便在处理期间不再遍历同一节点那些递归调用。但我仍然没有得到正确的输出。这是我做的修改:

INITIAL CODE BLOCK:

if(temp==null)
{
   findPaths(nextNode,dest);
   temp = hashMap.get(nextNode);
}

现在将上面的块改为以下内容:

if(temp==null)
{

      if(!inProcess.contains(nextNode))
      {
           inProcess.add(nextNode);
           findPaths(nextNode,dest);
           inProcess.remove(inProcess.indexOf(nextNode));
           temp = hashMap.get(nextNode);
      }
      else
      {
           continue main_for1;  //main_for1 labels the very first for() loop of this method
      }


}

我觉得这种修改在某种程度上是不够的。谁能告诉我什么是错的并纠正我?

2 个答案:

答案 0 :(得分:0)

我认为您的问题可能是主要声明的第一行:

  

int nextNode = allEdges.get(i).getEndNode();

这到底是做什么的?在我看来,当你第一次通过路径时,当你还没有弄清楚i的结束节点时,它会返回null。

答案 1 :(得分:0)

我想我已经修好了!我发现了两个问题。第一:在递归调用之前(在if-else之前),我们有代码:

int nextNode = allEdges.get(i).getEndNode();
ArrayList<Route> temp = hashMap.get(nextNode);

然后,如果tempnull,它会跳转到递归调用,但在递归调用之后,hashMap.get(nextNode)可以返回非空的内容。因此,您希望在if语句之后执行该部分。我这样修好了:

      int nextNode = currentEdge.getEndNode();
      ArrayList<Route> temp = hashMap.get(nextNode);
      if(temp==null) {
           findPaths(nextNode, dest);
           temp = hashMap.get(nextNode);
      }

      if(temp!=null) {
 for1:     for(j=0;j<temp.size();j++) {
       //...

我发现的第二个问题是:

stack.addAll(path);

ArrayList<Route> list3 = hashMap.get(source);
if(list3!=null) {
    list3.add(new Route(source,dest,stack));
    hashMap.put(source,list3);
} else {
    ArrayList<Route> list4 = new ArrayList();
    list4.add(new Route(source,dest,stack));
    hashMap.put(source,list4);
}

stack.removeAll(path);

请注意,在将路径插入hashmap之前添加堆栈并从之后删除。在if-else语句中创建的路由对象引用相同的堆栈,以便更改在那里保存的内容。你想要的是制作这样的副本:

ArrayList<Route> list3 = hashMap.get(source);
ArrayList<Integer> copy = new ArrayList<Integer>(stack);
if(list3!=null) {
    list3.add(new Route(source, dest,copy));
    hashMap.put(source,list3);
} else {
    ArrayList<Route> list4 = new ArrayList<Route>();
    list4.add(new Route(source, dest, copy));
    hashMap.put(source,list4);
}
stack.removeAll(path);

下面列出了整个功能。很抱歉弄乱了格式化。

static void findPaths(int source, int dest) {
    int i, j, k;
    for (i = 0; i < allEdges.size(); i++) {
        Edge currentEdge = allEdges.get(i);
        if (currentEdge.getStartNode() == source) {
            ArrayList<Integer> stack = new ArrayList<Integer>();
            stack.add(i); // pushing edge index to stack
            if (currentEdge.getEndNode() == dest) {
                ArrayList<Route> list1 = hashMap.get(source);

                if (list1 != null) {
                    list1.add(new Route(source, dest, stack));
                } else {
                    ArrayList<Route> list2 = new ArrayList<Route>();
                    list2.add(new Route(source, dest, stack));
                    hashMap.put(source, list2);
                }

            } else {
                int nextNode = currentEdge.getEndNode();
                ArrayList<Route> temp = hashMap.get(nextNode);
                if (temp == null) {
                    findPaths(nextNode, dest);
                    temp = hashMap.get(nextNode);
                }

                if (temp != null) {
                    for1: for (j = 0; j < temp.size(); j++) {
                        ArrayList<Integer> path = temp.get(j)
                                .getEdgeIndices();

                        for (k = 0; k < path.size(); k++) {
                            int edgeIndex = (int) path.get(k);
                            Edge ed = allEdges.get(edgeIndex);
                            if (ed.getStartNode() == source) {
                                continue for1;
                            }
                        }

                        stack.addAll(path);
                        ArrayList<Integer> copy = new ArrayList<Integer>(stack);
                        ArrayList<Route> list3 = hashMap.get(source);
                        if (list3 != null) {
                            list3.add(new Route(source, dest,copy));
                        } else {
                            ArrayList<Route> list4 = new ArrayList<Route>();
                            list4.add(new Route(source, dest, copy));
                            hashMap.put(source, list4);
                        }
                        stack.removeAll(path);
                    }
                }
            }
        }
    }
}