2012-03-21 336 views
2

早上好!用DFS查找图中的所有路径

我正在开发一种算法来查找无向图中的所有路径。我目前正在使用带回溯的DFS algortihm来尝试这样做。这是我现在的代码:

import java.util.*; 

public class dfs { 

    private static Map<Integer, LinkedHashSet<Integer>> map = new HashMap<Integer, LinkedHashSet<Integer>>(); 
    private int startNode; 
    private int numLinks; 

    public dfs(int startNode, int numLinks) { 
     super(); 
     this.startNode = startNode; 
     this.numLinks = numLinks; 
    } 

    public void addEdge(int source, int destiny) { 
     LinkedHashSet<Integer> adjacente = map.get(source); 
     if(adjacente==null) { 
      adjacente = new LinkedHashSet<Integer>(); 
      map.put(source, adjacente); 
     } 
     adjacente.add(destiny); 
    } 

    public void addLink(int source, int destiny) { 
     addEdge(source, destiny); 
     addEdge(destiny, source); 
    } 

    public LinkedList<Integer> adjacentNodes(int last) { 
     LinkedHashSet<Integer> adjacente = map.get(last); 
     System.out.println("adjacentes:" + adjacente); 
     if(adjacente==null) { 
      return new LinkedList<Integer>(); 
     } 
     return new LinkedList<Integer>(adjacente); 
    } 


public static void main(String[] args) { 

    Scanner input = new Scanner(System.in); 

    int numVertices = input.nextInt(); 
    int numLinks = input.nextInt(); 
    int startNode = input.nextInt(); 
    int endNode = startNode; 

    dfs mapa = new dfs(startNode, numLinks); 

    for(int i = 0; i<numLinks; i++){ 
     mapa.addLink(input.nextInt(), input.nextInt()); 
    } 

    List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>(); 
    List<Integer> visited = new ArrayList<Integer>(); 
    visited.add(startNode); 
    Integer currentNode = 0; 

    Iterator it = map.entrySet().iterator(); 
    while (it.hasNext()) { 
     Map.Entry pairs = (Map.Entry)it.next(); 
     currentNode = (Integer) pairs.getKey(); 
     //System.out.println("Current Node:" + currentNode); 
     mapa.findAllPaths(mapa, visited, paths, currentNode); 

    } 
} 

private void findAllPaths(dfs mapa, List<Integer> visited, 
     List<ArrayList<Integer>> paths, Integer currentNode) { 

    if (currentNode.equals(startNode)) { 
     paths.add(new ArrayList<Integer>(visited)); 

     LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode); 
     //System.out.println("visited:" + visited); 

     for (Integer node : nodes) { 
      //System.out.println("nodes:" + nodes); 
      List<Integer> temp = new ArrayList<Integer>(); 
      temp.addAll(visited); 
      temp.add(node);   
      findAllPaths(mapa, temp, paths, node); 
     } 

    } 

    else { 
     LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode); 
     System.out.println("currentNode:" + currentNode); 
     //System.out.println("nodes:" + nodes); 
     for (Integer node : nodes) {    
      if (visited.contains(node)) { 
       continue; 
      } 
      List<Integer> temp = new ArrayList<Integer>(); 
      temp.addAll(visited); 
      System.out.println("visited:" + visited); 
      temp.add(node);   
      findAllPaths(mapa, temp, paths, node); 
     } 
    } 

} 

} 

该程序在他的输入接收整数。第一个是节点数量,第二个是链接数量,第三个是开始节点和结束音符,它们是相同的。所有后面的整数表示节点之间的连接。

问题是,该算法找到的所有路径只访问一次单个节点。我想要的是查找所有访问每个连接的路径的算法。 关于如何做到这一点的任何想法?

+0

节点之间的连接如何表示为整数?我不太明白。 – 2012-03-21 11:03:32

+0

一个例子,程序收到“1 2 3 3 4 5 6”1是节点的数量,2是链接的数量,3是起始节点,3 4是从节点3到节点4的连接,5 6是从节点5到6的连接。 – 2012-03-21 11:42:13

回答

1

你正处在正确的轨道上 - 回溯是解决问题的好方法。

要获得所有的路径是“使用相同的边缘只有一次”: 你findAllPaths()使用边缘之后 - 从边缘集[删除这条边的每个顶点的LinkedHashSet连接]中删除它 - 以递归方式调用。

从递归返回后 - 不要忘记“清理环境”并将此边添加回两个顶点。

您需要确保在修改时不会遇到迭代集合的麻烦。 [你做不到 - 这样做的结果是意外的] - 所以你可能需要发送LinkedHashSet的副本[没有相关的边缘] - 而不是原来的。

+0

@CláudioRibeiro:查看构造函数[LinkedHashSet(Collection)](http://docs.oracle.com/javase/1.4.2/docs/api/java/util/ LinkedHashSet.html#LinkedHashSet%28java.util.Collection%29)使用它 - 您可以创建原始集的副本,并从副本中删除元素。 – amit 2012-03-21 12:43:27

+0

看着我的代码,是不是有其他方法让程序重复他已经访问过的节点?只有当他到达起始节点和被访问节点列表时,停止搜索等于输入给定的连接数。我真的无法让哈希集合做我想做的事... – 2012-03-21 15:12:17

+1

@CláudioRibeiro:你可以维护一个'visited'设置边缘并在递归调用'findPaths()'之前添加一个元素,并将其从在递归调用之后。您需要确保在for循环中不“重复”'visited'边缘:'for(Integer node:nodes){'[添加一些条件以确保您使用的边缘尚未访问] – amit 2012-03-21 15:18:07