+ Search Problems
+
+
+ A state space.
+
+
+ A successor function (with actions, costs).
+
+
+ A start state and a goal test.
+
+
+ A solution is a sequence of actions (a plan) which transforms the start state to a goal state.
+
+
+
+ State Space Graphs vs. Search Trees
+
+ Search Algorithms
+
+
+ Uninformed search algorithms (blind search).
+
+
+ Depth-First Search
+
+
+ Breadth-First Search
+
+
+ Uniform-Cost Search
+
+
+
+
+
+ Informed search algorithms (heuristic search).
+
+
+ Depth-First Search
+
+
+ Completeness: could be infinite, so only if we
+ prevent cycles.
+
+
+ Optimality: No, it finds the "leftmost" solution, regardless of
+ depth or cost.
+
+
+
+ Breadth-First Search
+
+
+ Completeness: must be finite if a solution exists
+ , so yes!
+
+
+ Optimality: Only if costs are all 1.
+
+
+
+
+ For more information on DFS & BFS, please visit DFS & BFS in Data
+ Structures and Algorithms.
+
+ Iterative Deepening: get DFS’s space advantage with BFS's
+ time / shallow solution advantages, run Run a DFS with depth limit 1, 2, 3, ...
+ Uniform Cost Search: Expand the node with the lowest path cost.
+
+
+ Dequeue the node with the lowest path cost (current_node).
+
+
+ If current_node is the goal state, reconstruct and return the path.
+
+
+ Expand current_node: For each successor (neighbor) of current_node,
+
+
+ If the successor is not in the explored set and not already in the priority queue, create
+ a new node for the successor with the calculated cost and parent set to current_node,
+ and insert the successor node into the priority queue.
+
+
+ Else if the successor is already in the priority queue with a higher cost, update the
+ successor's cost in the priority queue and its parent to current_node.
+
+
+
+
+
+
+
+ import java.util.*;
+
+ class Node implements Comparable<Node> {
+ String state;
+ Node parent;
+ int cost;
+
+ public Node(String state, Node parent, int cost) {
+ this.state = state;
+ this.parent = parent;
+ this.cost = cost;
+ }
+
+ @Override
+ public int compareTo(Node other) {
+ return Integer.compare(this.cost, other.cost);
+ }
+ }
+
+ public class UCS {
+
+ public static List<String> uniformCostSearch(Map<String, Map<String, Integer>> graph, String start, String goal) {
+ PriorityQueue<Node> priorityQueue = new PriorityQueue<>();
+ priorityQueue.offer(new Node(start, null, 0));
+ Set<String> explored = new HashSet<>();
+
+ while (!priorityQueue.isEmpty()) {
+ Node current = priorityQueue.poll();
+
+ if (current.state.equals(goal)) {
+ List<String> path = new ArrayList<>();
+ while (current != null) {
+ path.add(current.state);
+ current = current.parent;
+ }
+ Collections.reverse(path);
+ return path;
+ }
+
+ explored.add(current.state);
+
+ Map<String, Integer> successors = graph.getOrDefault(current.state, Collections.emptyMap());
+ for (Map.Entry<String, Integer> entry : successors.entrySet()) {
+ String successor = entry.getKey();
+ int cost = entry.getValue();
+ Node successorNode = new Node(successor, current, current.cost + cost);
+
+ if (!explored.contains(successor)) {
+ boolean inQueue = false;
+ for (Node n : priorityQueue) {
+ if (n.state.equals(successor)) {
+ inQueue = true;
+ if (n.cost > successorNode.cost) {
+ priorityQueue.remove(n); // Remove higher cost node
+ priorityQueue.offer(successorNode); // Add lower cost node
+ break; // Important: Exit loop after updating
+ }
+ }
+ }
+ if (!inQueue) {
+ priorityQueue.offer(successorNode);
+ }
+ }
+ }
+ }
+
+ return null; // No path found
+ }
+ }
+
+
+
+
+ import heapq
+
+ class Node:
+ def __init__(self, state, parent=None, cost=0):
+ self.state = state
+ self.parent = parent
+ self.cost = cost
+
+ def __lt__(self, other):
+ return self.cost < other.cost
+
+ def uniform_cost_search(graph, start, goal):
+ priority_queue = []
+ heapq.heappush(priority_queue, Node(start))
+ explored = set()
+
+ while priority_queue:
+ current_node = heapq.heappop(priority_queue)
+
+ if current_node.state == goal:
+ path = []
+ while current_node:
+ path.append(current_node.state)
+ current_node = current_node.parent
+ return path[::-1]
+
+ explored.add(current_node.state)
+
+ for successor, cost in graph.get(current_node.state, {}).items(): # Directly access successors and costs
+ successor_node = Node(successor, current_node, current_node.cost + cost)
+
+
+ if successor not in explored:
+ in_queue = False
+ for i, node in enumerate(priority_queue):
+ if node.state == successor:
+ in_queue = True
+ if node.cost > successor_node.cost:
+ priority_queue[i] = successor_node
+ heapq.heapify(priority_queue)
+ break
+
+ if not in_queue:
+ heapq.heappush(priority_queue, successor_node)
+
+
+ return None
+
+
+
+
+