📜  统一成本搜索(Dijkstra用于大图)

📅  最后修改于: 2021-05-05 00:12:57             🧑  作者: Mango

统一成本搜索是Dijikstra算法的一种变体。在这里,我们不插入所有顶点到优先级队列中,而是仅插入源,然后在需要时一个接一个地插入。在每一步中,我们都会检查该项目是否已经在优先级队列中(使用访问数组)。如果是,我们执行减少键,否则我们将其插入。
Dijsktra的这种变体对于无限图和太大而无法在内存中表示的图很有用。统一成本搜索主要用于人工智能。
例子:

Input :

Output :
Minimum cost from S to G is =3

均匀成本搜索类似于Dijikstra的算法。在此算法中,从开始状态开始,我们将访问相邻状态并选择成本最低的状态,然后从访问状态的所有未访问状态和相邻状态中选择下一个成本最低的状态,这样我们将尝试达到目标状态(请注意,我们不会继续通过目标状态的路径),即使我们达到目标状态,我们也会继续搜索其他可能的路径(如果有多个目标)。我们将保留一个优先级队列,该优先级队列将使从访问状态的所有相邻状态中开销最小的下一状态开始。

CPP
// C++ implemenatation of above approach
#include 
using namespace std;
 
// graph
vector > graph;
 
// map to store cost of edges
map, int> cost;
 
// returns the minimum cost in a vector( if
// there are multiple goal states)
vector uniform_cost_search(vector goal, int start)
{
    // minimum cost upto
    // goal state from starting
    // state
    vector answer;
 
    // create a priority queue
    priority_queue > 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 visited;
 
    // count
    int count = 0;
 
    // while the queue is not empty
    while (queue.size() > 0) {
 
        // get the top element of the
        // priority queue
        pair 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 goal;
 
    // set the goal
    // there can be multiple goal states
    goal.push_back(6);
 
    // get the answer
    vector answer = uniform_cost_search(goal, 0);
 
    // print the answer
    cout << "Minimum cost from 0 to 6 is = "
         << answer[0] << endl;
 
    return 0;
}


Python3
# Python3 implemenatation 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)
 
    # prthe answer
    print("Minimum cost from 0 to 6 is = ",answer[0])
 
# This code is contributed by mohit kumar 29


C#
// C# implemenatation of above approach
using System;
using System.Collections;
using System.Collections.Generic;
 
class GFG
{
 
// graph
static List> graph=new List>();
 
// map to store cost of edges
static Dictionary,int> cost= new Dictionary,int>();
 
// returns the minimum cost in a vector( if
// there are multiple goal states)
static List uniform_cost_search(List goal, int start)
{
    // minimum cost upto
    // goal state from starting
    // state
    List answer=new List();
 
    // create a priority queue
    List > queue = new List >();
 
    // 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(0, start));
 
    // map to store visited node
    Dictionary visited=new Dictionary();
 
    // count
    int count = 0;
 
    // while the queue is not empty
    while (queue.Count > 0) {
 
        // get the top element of the
        // priority queue
        Tuple q = queue[0];
        Tuple p = new Tuple(-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((p.Item1 + (cost.ContainsKey(new Tuple(p.Item2, graph[p.Item2][i])) ? cost[new Tuple(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>();
 
    for(int i=0;i<7;i++)
    {
        graph.Add(new List());
    }
 
    // 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(0, 1)] = 2;
    cost[new Tuple(0, 3)] = 5;
    cost[new Tuple(1, 6)] = 1;
    cost[new Tuple(3, 1)] = 5;
    cost[new Tuple(3, 6)] = 6;
    cost[new Tuple(3, 4)] = 2;
    cost[new Tuple(2, 1)] = 4;
    cost[new Tuple(4, 2)] = 4;
    cost[new Tuple(4, 5)] = 3;
    cost[new Tuple(5, 2)] = 6;
    cost[new Tuple(5, 6)] = 3;
    cost[new Tuple(6, 4)] = 7;
 
    // goal state
    List goal=new List();
 
    // set the goal
    // there can be multiple goal states
    goal.Add(6);
 
    // get the answer
    List 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.


输出:
Minimum cost from 0 to 6 is = 3

复杂度: O(m ^(1 + floor(l / e)))
在哪里,
m是节点具有的最大邻居数
l是到达目标状态的最短路径的长度
e是最小的边成本