Open In App
Related Articles

Uniform-Cost Search (Dijkstra for large Graphs)

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Report issue
Report

Uniform-Cost Search is a variant of Dijikstra’s algorithm. Here, instead of inserting all vertices into a priority queue, we insert only the source, then one by one insert when needed. In every step, we check if the item is already in the priority queue (using the visited array). If yes, we perform the decrease key, else we insert it.

This variant of Dijkstra is useful for infinite graphs and that graph which are too large to represent in memory. Uniform-Cost Search is mainly used in Artificial Intelligence.

Examples:

Input :

Output :
Minimum cost from S to G is =3

Uniform-Cost Search is similar to Dijikstra’s algorithm. In this algorithm from the starting state, we will visit the adjacent states and will choose the least costly state then we will choose the next least costly state from the all un-visited and adjacent states of the visited states, in this way we will try to reach the goal state (note we won’t continue the path through a goal state ), even if we reach the goal state we will continue searching for other possible paths( if there are multiple goals). We will keep a priority queue that will give the least costly next state from all the adjacent states of visited states.

C++

// C++ implementation of above approach
 
#include <bits/stdc++.h>
 
using namespace std;
 
// graph
vector<vector<int> > graph;
 
// map to store cost of edges
map<pair<int, int>, int> cost;
 
// returns the minimum cost in a vector( if
// there are multiple goal states)
vector<int> uniform_cost_search(vector<int> goal, int start)
{
    // minimum cost upto
    // goal state from starting
    // state
    vector<int> answer;
 
    // create a priority queue
    priority_queue<pair<int, int> > queue;
 
    // set the answer vector to max value
    for (int i = 0; i < goal.size(); i++)
        answer.push_back(INT_MAX);
 
    // insert the starting index
    queue.push(make_pair(0, start));
 
    // map to store visited node
    map<int, int> visited;
 
    // count
    int count = 0;
 
    // while the queue is not empty
    while (queue.size() > 0) {
 
        // get the top element of the
        // priority queue
        pair<int, int> p = queue.top();
 
        // pop the element
        queue.pop();
 
        // get the original value
        p.first *= -1;
 
        // check if the element is part of
        // the goal list
        if (find(goal.begin(), goal.end(), p.second) != goal.end()) {
 
            // get the position
            int index = find(goal.begin(), goal.end(),
                             p.second) - goal.begin();
 
            // if a new goal is reached
            if (answer[index] == INT_MAX)
                count++;
 
            // if the cost is less
            if (answer[index] > p.first)
                answer[index] = p.first;
 
            // pop the element
            queue.pop();
 
            // if all goals are reached
            if (count == goal.size())
                return answer;
        }
 
        // check for the non visited nodes
        // which are adjacent to present node
        if (visited[p.second] == 0)
            for (int i = 0; i < graph[p.second].size(); i++) {
 
                // value is multiplied by -1 so that
                // least priority is at the top
                queue.push(make_pair((p.first +
                  cost[make_pair(p.second, graph[p.second][i])]) * -1,
                  graph[p.second][i]));
            }
 
        // mark as visited
        visited[p.second] = 1;
    }
 
    return answer;
}
 
// main function
int main()
{
    // create the graph
    graph.resize(7);
 
    // add edge
    graph[0].push_back(1);
    graph[0].push_back(3);
    graph[3].push_back(1);
    graph[3].push_back(6);
    graph[3].push_back(4);
    graph[1].push_back(6);
    graph[4].push_back(2);
    graph[4].push_back(5);
    graph[2].push_back(1);
    graph[5].push_back(2);
    graph[5].push_back(6);
    graph[6].push_back(4);
 
    // add the cost
    cost[make_pair(0, 1)] = 2;
    cost[make_pair(0, 3)] = 5;
    cost[make_pair(1, 6)] = 1;
    cost[make_pair(3, 1)] = 5;
    cost[make_pair(3, 6)] = 6;
    cost[make_pair(3, 4)] = 2;
    cost[make_pair(2, 1)] = 4;
    cost[make_pair(4, 2)] = 4;
    cost[make_pair(4, 5)] = 3;
    cost[make_pair(5, 2)] = 6;
    cost[make_pair(5, 6)] = 3;
    cost[make_pair(6, 4)] = 7;
 
    // goal state
    vector<int> goal;
 
    // set the goal
    // there can be multiple goal states
    goal.push_back(6);
 
    // get the answer
    vector<int> answer = uniform_cost_search(goal, 0);
 
    // print the answer
    cout << "Minimum cost from 0 to 6 is = "
         << answer[0] << endl;
 
    return 0;
}

                    

Java

// Java implementation of above approach
 
import java.util.*;
 
public class GFG {
 
    // graph
    static List<List<Integer>> graph = new ArrayList<List<Integer>>();
 
    // map to store cost of edges
    static HashMap<List<Integer>, Integer> cost = new HashMap<List<Integer>, Integer>();
 
// returns the minimum cost in a vector( if
// there are multiple goal states)
    static List<Integer> uniform_cost_search(List<Integer> goal, int start) {
 
    // minimum cost upto
    // goal state from starting
    // state
        List<Integer> answer = new ArrayList<Integer>();
 
        // create a priority queue
        List<Tuple<Integer, Integer>> queue = new ArrayList<Tuple<Integer, Integer>>();
 
        // set the answer vector to max value
        for (int i = 0; i < goal.size(); i++)
            answer.add(Integer.MAX_VALUE);
 
        // insert the starting index
        queue.add(new Tuple<Integer, Integer>(0, start));
 
        // map to store visited node
        HashMap<Integer, Integer> visited = new HashMap<Integer, Integer>();
 
        // count
        int count = 0;
 
        // while the queue is not empty
        while (!queue.isEmpty()) {
 
        // get the top element of the
        // priority queue
            Tuple<Integer, Integer> q = queue.get(0);
            Tuple<Integer, Integer> p = new Tuple<Integer, Integer>(-q.x, q.y);
 
            // pop the element
            queue.remove(0);
 
            if (goal.contains(p.y)) {
                // get the position
                int index = goal.indexOf(p.y);
                // if a new goal is reached
                if (answer.get(index) == Integer.MAX_VALUE)
                    count++;
                // if the cost is less
                if (answer.get(index) > p.x)
                    answer.set(index, p.x);
                // pop the element
                queue.remove(0);
                // if all goals are reached
                if (count == goal.size())
                    return answer;
            }
            if (!visited.containsKey(p.y))
                for (int i = 0; i < graph.get(p.y).size(); i++) {
                // value is multiplied by -1 so that
                // least priority is at the top
                    queue.add(new Tuple<Integer, Integer>((p.x + (cost.containsKey(Arrays.asList(p.y, graph.get(p.y).get(i))) ? cost.get(Arrays.asList(p.y, graph.get(p.y).get(i))) : 0)) * -1,
                            graph.get(p.y).get(i)));
                }
 
            // mark as visited
            visited.put(p.y, 1);
        }
 
        return answer;
    }
 
    // main function
    public static void main(String[] args) {
        // create the graph
        graph = new ArrayList<List<Integer>>();
 
        for (int i = 0; i < 7; i++) {
            graph.add(new ArrayList<Integer>());
        }
         
        // add edges
        graph.get(0).add(1);
        graph.get(0).add(3);
        graph.get(3).add(1);
        graph.get(3).add(6);
        graph.get(3).add(4);
        graph.get(1).add(6);
        graph.get(4).add(2);
        graph.get(4).add(5);
        graph.get(2).add(1);
        graph.get(5).add(2);
        graph.get(5).add(6);
        graph.get(6).add(4);
 
        // add the cost
        cost.put(Arrays.asList(0, 1), 2);
        cost.put(Arrays.asList(0, 3), 5);
        cost.put(Arrays.asList(1, 6), 1);
        cost.put(Arrays.asList(3, 1), 5);
        cost.put(Arrays.asList(3, 6), 6);
        cost.put(Arrays.asList(3, 4), 2);
        cost.put(Arrays.asList(2, 1), 4);
        cost.put(Arrays.asList(4, 2), 4);
        cost.put(Arrays.asList(4, 5), 3);
        cost.put(Arrays.asList(5, 2), 6);
        cost.put(Arrays.asList(5, 6), 3);
        cost.put(Arrays.asList(6, 4), 7);
 
        // goal state
        List<Integer> goal = new ArrayList<Integer>();
        goal.add(6);
 
        List<Integer> answer = uniform_cost_search(goal, 0);
 
        // print the answer
        System.out.print("Minimum cost from 0 to 6 is = " + answer.get(0));
    }
}
 
class Tuple<X, Y> {
    public final X x;
    public final Y y;
 
    public Tuple(X x, Y y) {
        this.x = x;
        this.y = y;
    }
}

                    

Python3

# Python3 implementation of above approach
 
# returns the minimum cost in a vector( if
# there are multiple goal states)
def  uniform_cost_search(goal, start):
     
    # minimum cost upto
    # goal state from starting
    global graph,cost
    answer = []
 
    # create a priority queue
    queue = []
 
    # set the answer vector to max value
    for i in range(len(goal)):
        answer.append(10**8)
 
    # insert the starting index
    queue.append([0, start])
 
    # map to store visited node
    visited = {}
 
    # count
    count = 0
 
    # while the queue is not empty
    while (len(queue) > 0):
 
        # get the top element of the
        queue = sorted(queue)
        p = queue[-1]
 
        # pop the element
        del queue[-1]
 
        # get the original value
        p[0] *= -1
 
        # check if the element is part of
        # the goal list
        if (p[1] in goal):
 
            # get the position
            index = goal.index(p[1])
 
            # if a new goal is reached
            if (answer[index] == 10**8):
                count += 1
 
            # if the cost is less
            if (answer[index] > p[0]):
                answer[index] = p[0]
 
            # pop the element
            del queue[-1]
 
            queue = sorted(queue)
            if (count == len(goal)):
                return answer
 
        # check for the non visited nodes
        # which are adjacent to present node
        if (p[1] not in visited):
            for i in range(len(graph[p[1]])):
 
                # value is multiplied by -1 so that
                # least priority is at the top
                queue.append( [(p[0] + cost[(p[1], graph[p[1]][i])])* -1, graph[p[1]][i]])
 
        # mark as visited
        visited[p[1]] = 1
 
    return answer
 
# main function
if __name__ == '__main__':
     
    # create the graph
    graph,cost = [[] for i in range(8)],{}
 
    # add edge
    graph[0].append(1)
    graph[0].append(3)
    graph[3].append(1)
    graph[3].append(6)
    graph[3].append(4)
    graph[1].append(6)
    graph[4].append(2)
    graph[4].append(5)
    graph[2].append(1)
    graph[5].append(2)
    graph[5].append(6)
    graph[6].append(4)
 
    # add the cost
    cost[(0, 1)] = 2
    cost[(0, 3)] = 5
    cost[(1, 6)] = 1
    cost[(3, 1)] = 5
    cost[(3, 6)] = 6
    cost[(3, 4)] = 2
    cost[(2, 1)] = 4
    cost[(4, 2)] = 4
    cost[(4, 5)] = 3
    cost[(5, 2)] = 6
    cost[(5, 6)] = 3
    cost[(6, 4)] = 7
 
    # goal state
    goal = []
 
    # set the goal
    # there can be multiple goal states
    goal.append(6)
 
    # get the answer
    answer = uniform_cost_search(goal, 0)
 
    # print the answer
    print("Minimum cost from 0 to 6 is = ",answer[0])
 
# This code is contributed by mohit kumar 29

                    

C#

// C# implementation of above approach
using System;
using System.Collections;
using System.Collections.Generic;
 
class GFG
{
 
// graph
static List<List<int>> graph=new List<List<int>>();
 
// map to store cost of edges
static Dictionary<Tuple<int,int>,int> cost= new Dictionary<Tuple<int,int>,int>();
 
// returns the minimum cost in a vector( if
// there are multiple goal states)
static List<int> uniform_cost_search(List<int> goal, int start)
{
    // minimum cost upto
    // goal state from starting
    // state
    List<int> answer=new List<int>();
 
    // create a priority queue
    List<Tuple<int, int> > queue = new List<Tuple<int, int> >();
 
    // set the answer vector to max value
    for (int i = 0; i < goal.Count; i++)
        answer.Add(int.MaxValue);
 
    // insert the starting index
    queue.Add(new Tuple<int,int>(0, start));
 
    // map to store visited node
    Dictionary<int, int> visited=new Dictionary<int,int>();
 
    // count
    int count = 0;
 
    // while the queue is not empty
    while (queue.Count > 0) {
 
        // get the top element of the
        // priority queue
        Tuple<int, int> q = queue[0];
        Tuple<int, int> p = new Tuple<int,int>(-q.Item1,q.Item2);
 
        // pop the element
        queue.RemoveAt(0);
 
 
        // check if the element is part of
        // the goal list
        if (goal.Contains(p.Item2)) {
 
            // get the position
            int index = goal.IndexOf(p.Item2);
 
            // if a new goal is reached
            if (answer[index] == int.MaxValue)
                count++;
 
            // if the cost is less
            if (answer[index] > p.Item1)
                answer[index] = p.Item1;
 
            // pop the element
            queue.RemoveAt(0);
 
            // if all goals are reached
            if (count == goal.Count)
                return answer;
        }
 
        // check for the non visited nodes
        // which are adjacent to present node
        if (!visited.ContainsKey(p.Item2))
            for (int i = 0; i < graph[p.Item2].Count; i++) {
 
                // value is multiplied by -1 so that
                // least priority is at the top
                queue.Add(new Tuple<int,int>((p.Item1 + (cost.ContainsKey(new Tuple<int,int>(p.Item2, graph[p.Item2][i])) ? cost[new Tuple<int,int>(p.Item2, graph[p.Item2][i])] : 0))*-1,
                graph[p.Item2][i]));
            }
 
        // mark as visited
        visited[p.Item2] = 1;
    }
 
    return answer;
}
 
// main function
public static void Main(params string []args)
{
    // create the graph
    graph=new List<List<int>>();
 
    for(int i=0;i<7;i++)
    {
        graph.Add(new List<int>());
    }
 
    // add edge
    graph[0].Add(1);
    graph[0].Add(3);
    graph[3].Add(1);
    graph[3].Add(6);
    graph[3].Add(4);
    graph[1].Add(6);
    graph[4].Add(2);
    graph[4].Add(5);
    graph[2].Add(1);
    graph[5].Add(2);
    graph[5].Add(6);
    graph[6].Add(4);
 
    // add the cost
    cost[new Tuple<int,int>(0, 1)] = 2;
    cost[new Tuple<int,int>(0, 3)] = 5;
    cost[new Tuple<int,int>(1, 6)] = 1;
    cost[new Tuple<int,int>(3, 1)] = 5;
    cost[new Tuple<int,int>(3, 6)] = 6;
    cost[new Tuple<int,int>(3, 4)] = 2;
    cost[new Tuple<int,int>(2, 1)] = 4;
    cost[new Tuple<int,int>(4, 2)] = 4;
    cost[new Tuple<int,int>(4, 5)] = 3;
    cost[new Tuple<int,int>(5, 2)] = 6;
    cost[new Tuple<int,int>(5, 6)] = 3;
    cost[new Tuple<int,int>(6, 4)] = 7;
 
    // goal state
    List<int> goal=new List<int>();
 
    // set the goal
    // there can be multiple goal states
    goal.Add(6);
 
    // get the answer
    List<int> answer = uniform_cost_search(goal, 0);
 
    // print the answer
    Console.Write("Minimum cost from 0 to 6 is = " + answer[0]);
 
}
}
 
// This code is contributed by rutvik_56.

                    

Javascript

// returns the minimum cost in a vector( if
// there are multiple goal states)
function uniform_cost_search(goal, start) {
  // minimum cost upto
  // goal state from starting
  let answer = [];
 
  // create a priority queue
  let queue = [];
 
  // set the answer vector to max value
  for (let i = 0; i < goal.length; i++) {
    answer.push(10 ** 8);
  }
 
  // insert the starting index
  queue.push([0, start]);
 
  // map to store visited node
  let visited = {};
 
  // count
  let count = 0;
 
  // while the queue is not empty
  while (queue.length > 0) {
    // get the top element of the
    queue.sort();
    let p = queue[queue.length - 1];
 
    // pop the element
    queue.splice(queue.length - 1, 1);
 
    // get the original value
    p[0] *= -1;
 
    // check if the element is part of
    // the goal list
    if (goal.includes(p[1])) {
      // get the position
      let index = goal.indexOf(p[1]);
 
      // if a new goal is reached
      if (answer[index] === 10 ** 8) {
        count += 1;
      }
 
      // if the cost is less
      if (answer[index] > p[0]) {
        answer[index] = p[0];
      }
 
      // pop the element
      queue.splice(queue.length - 1, 1);
      queue.sort();
      if (count === goal.length) {
        return answer;
      }
    }
 
    // check for the non visited nodes
    // which are adjacent to present node
    if (!visited[p[1]]) {
      for (let i = 0; i < graph[p[1]].length; i++) {
        // value is multiplied by -1 so that
        // least priority is at the top
        queue.push([
          (p[0] + cost[p[1] + "," + graph[p[1]][i]]) * -1,
          graph[p[1]][i],
        ]);
      }
    }
 
    // mark as visited
    visited[p[1]] = true;
  }
 
  return answer;
}
 
// create the graph
let graph = [[], [], [], [], [], [], [], []];
let cost = {};
 
// add edge
graph[0].push(1);
graph[0].push(3);
graph[3].push(1);
graph[3].push(6);
graph[3].push(4);
graph[1].push(6);
graph[4].push(2);
graph[4].push(5);
graph[2].push(1);
graph[5].push(2);
graph[5].push(6);
graph[6].push(4);
 
// add the cost
cost["0,1"] = 2;
cost["0,3"] = 5;
cost["1,6"] = 1;
cost["3,1"] = 5;
cost["3,6"] = 6;
cost["3,4"] = 2;
cost["2,1"] = 4;
cost["4,2"] = 4;
cost["4,5"] = 3;
cost["5,2"] = 6;
cost["5,6"] = 3;
cost["6,4"] = 7;
 
// goal state
    goal = []
 
   // set the goal
   // there can be multiple goal states
    goal.push(6)
 
   // get the answer
    answer = uniform_cost_search(goal, 0)
 
   // print the answer
    console.log("Minimum cost from 0 to 6 is = ",answer[0])
     
    // This code is contributed by lokeshpotta20.

                    

Output: 
Minimum cost from 0 to 6 is = 3

 

Time Complexity: O( m ^ (1+floor(l/e))) 

where, 
m is the maximum number of neighbors a node has 
l is the length of the shortest path to the goal state 
e is the least cost of an edge
 



Last Updated : 20 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads