2013-12-17 53 views
3

我試圖在觀看Udacity中的「Intro to AI」課程後實施統一成本搜索。但是,我的算法沒有得到正確的路徑。在這裏發佈前一直在嘗試一整天。我添加了一張地圖來幫助可視化場景。該算法應找到從阿拉德到布加勒斯特的最短加權路徑Romania Map統一成本搜索實施

import java.util.PriorityQueue; 
import java.util.HashSet; 
import java.util.Set; 
import java.util.Collections; 
import java.util.List; 
import java.util.ArrayList; 
import java.util.Comparator; 

//diff between uniform cost search and dijkstra algo is that UCS has a goal 

public class UniformCostSearchAlgo{ 
    public static void main(String[] args){ 

     //initialize the graph base on the Romania map 
     Node n1 = new Node("Arad"); 
     Node n2 = new Node("Zerind"); 
     Node n3 = new Node("Oradea"); 
     Node n4 = new Node("Sibiu"); 
     Node n5 = new Node("Fagaras"); 
     Node n6 = new Node("Rimnicu Vilcea"); 
     Node n7 = new Node("Pitesti"); 
     Node n8 = new Node("Timisoara"); 
     Node n9 = new Node("Lugoj"); 
     Node n10 = new Node("Mehadia"); 
     Node n11 = new Node("Drobeta"); 
     Node n12 = new Node("Craiova"); 
     Node n13 = new Node("Bucharest"); 
     Node n14 = new Node("Giurgiu"); 

     //initialize the edges 
     n1.adjacencies = new Edge[]{ 
      new Edge(n2,75), 
      new Edge(n4,140), 
      new Edge(n8,118) 
     }; 

     n2.adjacencies = new Edge[]{ 
      new Edge(n1,75), 
      new Edge(n3,71) 
     }; 

     n3.adjacencies = new Edge[]{ 
      new Edge(n2,71), 
      new Edge(n4,151) 
     }; 

     n4.adjacencies = new Edge[]{ 
      new Edge(n1,140), 
      new Edge(n5,99), 
      new Edge(n3,151), 
      new Edge(n6,80), 
     }; 

     n5.adjacencies = new Edge[]{ 
      new Edge(n4,99), 
      new Edge(n13,211) 
     }; 

     n6.adjacencies = new Edge[]{ 
      new Edge(n4,80), 
      new Edge(n7,97), 
      new Edge(n12,146) 
     }; 

     n7.adjacencies = new Edge[]{ 
      new Edge(n6,97), 
      new Edge(n13,101), 
      new Edge(n12,138) 
     }; 

     n8.adjacencies = new Edge[]{ 
      new Edge(n1,118), 
      new Edge(n9,111) 
     }; 

     n9.adjacencies = new Edge[]{ 
      new Edge(n8,111), 
      new Edge(n10,70) 
     }; 

     n10.adjacencies = new Edge[]{ 
      new Edge(n9,70), 
      new Edge(n11,75) 
     }; 

     n11.adjacencies = new Edge[]{ 
      new Edge(n10,75), 
      new Edge(n12,120) 
     }; 

     n12.adjacencies = new Edge[]{ 
      new Edge(n11,120), 
      new Edge(n6,146), 
      new Edge(n7,138) 
     }; 

     n13.adjacencies = new Edge[]{ 
      new Edge(n7,101), 
      new Edge(n14,90), 
      new Edge(n5,211) 
     }; 

     n14.adjacencies = new Edge[]{ 
      new Edge(n13,90) 
     }; 

     UniformCostSearch(n1,n13); 

     List<Node> path = printPath(n13); 

     System.out.println("Path: " + path); 

    } 

    public static void UniformCostSearch(Node source, Node goal){ 

     source.pathCost = 0; 
     PriorityQueue<Node> queue = new PriorityQueue<Node>(20, 
      new Comparator<Node>(){ 

       //override compare method 
       public int compare(Node i, Node j){ 
        if(i.pathCost > j.pathCost){ 
         return 1; 
        } 

        else if (i.pathCost < j.pathCost){ 
         return -1; 
        } 

        else{ 
         return 0; 
        } 
       } 
      } 

     ); 

     queue.add(source); 
     Set<Node> explored = new HashSet<Node>(); 
     boolean found = false; 

     //while frontier is not empty 
     do{ 

      Node current = queue.poll(); 
      explored.add(current); 


      if(current.value.equals(goal.value)){ 
       found = true; 


      } 




      for(Edge e: current.adjacencies){ 
       Node child = e.target; 
       double cost = e.cost; 
       child.pathCost = current.pathCost + cost; 



       if(!explored.contains(child) && !queue.contains(child)){ 

        child.parent = current; 
        queue.add(child); 

        System.out.println(child); 
        System.out.println(queue); 
        System.out.println(); 

       } 


       else if((queue.contains(child))&&(child.pathCost>current.pathCost)){ 

        child.parent=current; 
        current = child; 

       } 


      } 
     }while(!queue.isEmpty()); 

    } 

    public static List<Node> printPath(Node target){ 
     List<Node> path = new ArrayList<Node>(); 
     for(Node node = target; node!=null; node = node.parent){ 
      path.add(node); 
     } 

     Collections.reverse(path); 

     return path; 

    } 

} 

class Node{ 

    public final String value; 
    public double pathCost; 
    public Edge[] adjacencies; 
    public Node parent; 

    public Node(String val){ 

     value = val; 

    } 

    public String toString(){ 
     return value; 
    } 

} 

class Edge{ 
    public final double cost; 
    public final Node target; 

    public Edge(Node targetNode, double costVal){ 
     cost = costVal; 
     target = targetNode; 

    } 
} 
+2

你在期待和你想說什麼? – Dom

+0

@Dom,我添加了一張地圖來解釋更多。我試圖找到從阿拉德到布加勒斯特的最短路線。路徑應該是[Arad,Sibiu,Rimnicu Vilcea,皮特什蒂,布加勒斯特]。但我越來越[Arad,Sibiu,Fagaras,布加勒斯特] –

+0

不要忘記接受答案。 –

回答

0

哇。我設法弄清楚了!顯然,我添加了雙向邊而不是單向邊。而不是讓Edge e1從節點A到節點B,邊e2從節點B到節點A,我刪除e2,使它成爲單個有向圖。因此,該算法起作用!

+0

但是該示例中的圖不是定向的,並且該算法應該適用於無向圖。此外,隊列可能有問題。 java.util.PriorityQueue並不是真正用於減少像在最短路徑算法中獲得的密鑰的密鑰。您可以通過刪除節點並重新添加它來獲得該效果,但這與預期的複雜程度不同。 'PriorityQueue'用於一旦對象被插入後鍵(/優先級)不會改變的情況。 –

0

您的算法的問題是當您找到已經在隊列中的節點的新的較短路徑時的部分。除了調用poll外,您不應該設置current,因爲這打破了算法方案。相反,您應該減少節點的密鑰/優先級/當前最短路徑開銷。

我已更新您的代碼來執行此操作。它提供了預期的結果。但正如我在評論中所說的那樣,當涉及到漸近複雜時,這不是最有效的解決方案。最好的選擇是找到或編寫一個支持動態密鑰的PriorityQueue

但這裏是更新後的代碼:統一成本與添加的路徑搜索的

import java.util.PriorityQueue; 
import java.util.HashSet; 
import java.util.Set; 
import java.util.Collections; 
import java.util.List; 
import java.util.ArrayList; 
import java.util.Comparator; 

//diff between uniform cost search and dijkstra algo is that UCS has a goal 

public class UniformCostSearchAlgo{ 
    public static void main(String[] args){ 

     //initialize the graph base on the Romania map 
     Node n1 = new Node("Arad"); 
     Node n2 = new Node("Zerind"); 
     Node n3 = new Node("Oradea"); 
     Node n4 = new Node("Sibiu"); 
     Node n5 = new Node("Fagaras"); 
     Node n6 = new Node("Rimnicu Vilcea"); 
     Node n7 = new Node("Pitesti"); 
     Node n8 = new Node("Timisoara"); 
     Node n9 = new Node("Lugoj"); 
     Node n10 = new Node("Mehadia"); 
     Node n11 = new Node("Drobeta"); 
     Node n12 = new Node("Craiova"); 
     Node n13 = new Node("Bucharest"); 
     Node n14 = new Node("Giurgiu"); 

     //initialize the edges 
     n1.adjacencies = new Edge[]{ 
      new Edge(n2,75), 
      new Edge(n4,140), 
      new Edge(n8,118) 
     }; 

     n2.adjacencies = new Edge[]{ 
      new Edge(n1,75), 
      new Edge(n3,71) 
     }; 

     n3.adjacencies = new Edge[]{ 
      new Edge(n2,71), 
      new Edge(n4,151) 
     }; 

     n4.adjacencies = new Edge[]{ 
      new Edge(n1,140), 
      new Edge(n5,99), 
      new Edge(n3,151), 
      new Edge(n6,80), 
     }; 

     n5.adjacencies = new Edge[]{ 
      new Edge(n4,99), 
      new Edge(n13,211) 
     }; 

     n6.adjacencies = new Edge[]{ 
      new Edge(n4,80), 
      new Edge(n7,97), 
      new Edge(n12,146) 
     }; 

     n7.adjacencies = new Edge[]{ 
      new Edge(n6,97), 
      new Edge(n13,101), 
      new Edge(n12,138) 
     }; 

     n8.adjacencies = new Edge[]{ 
      new Edge(n1,118), 
      new Edge(n9,111) 
     }; 

     n9.adjacencies = new Edge[]{ 
      new Edge(n8,111), 
      new Edge(n10,70) 
     }; 

     n10.adjacencies = new Edge[]{ 
      new Edge(n9,70), 
      new Edge(n11,75) 
     }; 

     n11.adjacencies = new Edge[]{ 
      new Edge(n10,75), 
      new Edge(n12,120) 
     }; 

     n12.adjacencies = new Edge[]{ 
      new Edge(n11,120), 
      new Edge(n6,146), 
      new Edge(n7,138) 
     }; 

     n13.adjacencies = new Edge[]{ 
      new Edge(n7,101), 
      new Edge(n14,90), 
      new Edge(n5,211) 
     }; 

     n14.adjacencies = new Edge[]{ 
      new Edge(n13,90) 
     }; 

     UniformCostSearch(n1,n13); 

     List<Node> path = printPath(n13); 

     System.out.println("Path: " + path); 

    } 

    public static void UniformCostSearch(Node source, Node goal){ 

     source.pathCost = 0; 
     PriorityQueue<Node> queue = new PriorityQueue<Node>(20, 
      new Comparator<Node>(){ 

       //override compare method 
       public int compare(Node i, Node j){ 
        if(i.pathCost > j.pathCost){ 
         return 1; 
        } 

        else if (i.pathCost < j.pathCost){ 
         return -1; 
        } 

        else{ 
         return 0; 
        } 
       } 
      } 

     ); 

     queue.add(source); 
     Set<Node> explored = new HashSet<Node>(); 
     boolean found = false; 

     //while frontier is not empty 
     do{ 

      Node current = queue.poll(); 
      explored.add(current); 


      if(current.value.equals(goal.value)){ 
       found = true; 


      } 




      for(Edge e: current.adjacencies){ 
       Node child = e.target; 
       double cost = e.cost; 
       child.pathCost = current.pathCost + cost; 



       if(!explored.contains(child) && !queue.contains(child)){ 

        child.parent = current; 
        queue.add(child); 

        System.out.println(child); 
        System.out.println(queue); 
        System.out.println(); 

       } 
       else if((queue.contains(child))&&(child.pathCost>current.pathCost)){ 
        child.parent=current; 

        // the next two calls decrease the key of the node in the queue 
        queue.remove(child); 
        queue.add(child); 
       } 


      } 
     }while(!queue.isEmpty()); 

    } 

    public static List<Node> printPath(Node target){ 
     List<Node> path = new ArrayList<Node>(); 
     for(Node node = target; node!=null; node = node.parent){ 
      path.add(node); 
     } 

     Collections.reverse(path); 

     return path; 

    } 

} 

class Node{ 

    public final String value; 
    public double pathCost; 
    public Edge[] adjacencies; 
    public Node parent; 

    public Node(String val){ 

     value = val; 

    } 

    public String toString(){ 
     return value; 
    } 

} 

class Edge{ 
    public final double cost; 
    public final Node target; 

    public Edge(Node targetNode, double costVal){ 
     cost = costVal; 
     target = targetNode; 

    } 
} 
+0

謝謝@Viktor。現在,如果我將Fagaras到Buscharest的距離更改爲更低的值(例如1),這將使路徑更短,則算法現在不會返回此新的較短路徑。當它現在應該是[Arad,Sibiu,Fagaras,Bucharest]時,它仍然保持[Arad,Sibiu,Rimnicu Vilcea,Pitesti,Bucharest]。有任何想法嗎? –

+0

@ Ray.R.Chua你能檢查你是否正確設置了邊長並重新編譯了?對我來說,更新的算法顯示預期的結果。查看ideone上的運行:http://ideone.com/KCqfXM –

0

這是解決問題的,什麼是錯在你的算法。

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.HashSet; 
import java.util.List; 
import java.util.PriorityQueue; 
import java.util.Set; 

public class UniformCostSearchAlgo { 

public static void main(String[] args) { 
Node n1 = new Node("Arad"); 
Node n2 = new Node("Zerind"); 
Node n3 = new Node("Oradea"); 
Node n4 = new Node("Sibiu"); 
Node n5 = new Node("Fagaras"); 
Node n6 = new Node("Rimnicu Vilcea"); 
Node n7 = new Node("Pitesti"); 
Node n8 = new Node("Timisoara"); 
Node n9 = new Node("Lugoj"); 
Node n10 = new Node("Mehadia"); 
Node n11 = new Node("Drobeta"); 
Node n12 = new Node("Craiova"); 
Node n13 = new Node("Bucharest"); 
Node n14 = new Node("Giurgiu"); 

// initialize the edges 
n1.adjacencies = new Edge[] { new Edge(n2, 75), new Edge(n4, 140), 
     new Edge(n8, 118) }; 

n2.adjacencies = new Edge[] { new Edge(n1, 75), new Edge(n3, 71) }; 

n3.adjacencies = new Edge[] { new Edge(n2, 71), new Edge(n4, 151) }; 

n4.adjacencies = new Edge[] { new Edge(n1, 140), new Edge(n5, 99), 
     new Edge(n3, 151), new Edge(n6, 80), }; 

n5.adjacencies = new Edge[] { new Edge(n4, 99), new Edge(n13, 211) }; 

n6.adjacencies = new Edge[] { new Edge(n4, 80), new Edge(n7, 97), 
     new Edge(n12, 146) }; 

n7.adjacencies = new Edge[] { new Edge(n6, 97), new Edge(n13, 101), 
     new Edge(n12, 138) }; 

n8.adjacencies = new Edge[] { new Edge(n1, 118), new Edge(n9, 111) }; 

n9.adjacencies = new Edge[] { new Edge(n8, 111), new Edge(n10, 70) }; 

n10.adjacencies = new Edge[] { new Edge(n9, 70), new Edge(n11, 75) }; 

n11.adjacencies = new Edge[] { new Edge(n10, 75), new Edge(n12, 120) }; 

n12.adjacencies = new Edge[] { new Edge(n11, 120), new Edge(n6, 146), 
     new Edge(n7, 138) }; 

n13.adjacencies = new Edge[] { new Edge(n7, 101), new Edge(n14, 90), 
     new Edge(n5, 211) }; 

n14.adjacencies = new Edge[] { new Edge(n13, 90) }; 

UniformCostSearch(n1, n13); 

List<Node> path = printPath(n13); 

System.out.println("Path: " + path); 

} 

public static void UniformCostSearch(Node source, Node goal) { 

List<Node> list = new ArrayList<Node>(); 
source.pathCost = 0; 
PriorityQueue<Node> queue = new PriorityQueue<Node>(20, 
     new Comparator<Node>() { 

      // override compare method 
      public int compare(Node i, Node j) { 
       if ((i.pathCost > j.pathCost)) { 
        return 1; 
       } 

       else if (i.pathCost < j.pathCost) { 
        return -1; 
       } 

       else { 
        return 0; 
       } 
      } 
     } 

); 

queue.add(source); 
Set<Node> explored = new HashSet<Node>(); 
List<Node> path = new ArrayList<Node>(); 

// while frontier is not empty 
do { 

    path.clear(); 
    Node current = queue.poll(); 
    explored.add(current); 
    for (Node node = current; node != null; node = node.parent) { 
     path.add(node); 
    } 
    if (current.value.equals(goal.value)) { 
     goal.parent = current.parent; 
     goal.pathCost = current.pathCost; 
     break; 

    } 

    for (Edge e : current.adjacencies) { 
     Node child = e.target; 
     double cost = e.cost; 
     if ((queue.contains(child) || explored.contains(child)) 
       && !path.contains(child)) { 
      Node n = new Node(child); 
      list.add(n); 
      list.get(list.size() - 1).pathCost = current.pathCost 
        + cost; 
      list.get(list.size() - 1).parent = current; 
      queue.add(list.get(list.size() - 1)); 

      System.out.println(list.get(list.size() - 1)); 
      System.out.println(queue); 
     } else if (!path.contains(child)) { 
      child.pathCost = current.pathCost + cost; 
      child.parent = current; 
      queue.add(child); 

      System.out.println(child); 
      System.out.println(queue); 
     } 

    } 
} while (!queue.isEmpty()); 

} 

public static List<Node> printPath(Node target) { 
List<Node> path = new ArrayList<Node>(); 
for (Node node = target; node != null; node = node.parent) { 
    path.add(node); 
} 

Collections.reverse(path); 

return path; 

} 
} 
class Node { 
public final String value; 
public double pathCost; 
public Edge[] adjacencies; 
public Node parent; 

public Node(String val) { 

value = val; 

} 

public Node(Node node) { 
int i = 0; 
adjacencies = new Edge[node.adjacencies.length]; 
value = node.value; 
pathCost = node.pathCost; 
for (Edge e : node.adjacencies) { 
    adjacencies[i++] = e; 
} 
parent = node.parent; 
} 

public String toString() { 
return value + pathCost + " "; 
} 

} 
class Edge { 
public final double cost; 
public final Node target; 

public Edge(Node targetNode, double costVal) { 
cost = costVal; 
target = targetNode; 

} 

} 
+0

請添加一句話來解釋您的代碼。 –

0

改變這部分的代碼

else if((queue.contains(child))&&(child.pathCost>current.pathCost)){ 

          child.parent=current; 
          current = child; 

        } 

else if((queue.contains(child))&&(child.pathCost>current.pathCost+cost)){ 

          child.parent=current; 
          child.pathCost = current.pathCost+cost; 
          queue.remove(child); 
          queue.add(child); 


        }