2013-12-17 56 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); 


        }