(10-5)优先级遍历(Priority-based Search)算法:“罗马尼亚之旅”的路径规划程序

本文介绍了一个基于图论的程序,用于帮助旅行者规划在罗马尼亚城市间的最短路径。通过用户输入起始和目标城市,程序利用最短路径算法计算并显示路径,适用于教学和旅行规划。
摘要由CSDN通过智能技术生成

10.5  “罗马尼亚之旅”的路径规划程序

本项目是一个基于图论的应用程序,旨在帮助旅行者规划在罗马尼亚各个城市之间的最短路径。本项目提供了一个简单易用的界面,让用户可以输入起始城市和目标城市,然后通过最短路径算法计算出两个城市之间的最短路径,并展示经过的所有城市。

实例10-4罗马尼亚之旅”的路径规划程序codes/10/Shortest_Path

10.5.1  项目背景介绍

随着旅游业的发展和人们对旅行的热情增长,规划旅行路线成为了一项重要的需求。而对于许多旅行者来说,找到最短路径是旅行规划中的关键一步。罗马尼亚作为一个旅游胜地,拥有着丰富的历史、文化和自然景观,吸引着众多游客前往。然而,对于游客来说,在罗马尼亚的各个城市之间规划最佳旅行路线可能会很复杂,尤其是当需要考虑到不同城市之间的距离、交通状况以及旅行时间等因素时。下图10-1展示了罗马尼亚的各个城市的距离信息。

图10-1  罗马尼亚的各个城市的距离信息

为了帮助旅行者更轻松地规划在罗马尼亚境内的旅行路线,我们开发了“罗马尼亚之旅”的路径规划程序。该项目利用图论中的最短路径算法,实现了一个简单易用的应用程序,可以根据用户输入的起始城市和目标城市,快速计算出两个城市之间的最短路径,并提供详细的路线信息。这样,旅行者可以更加方便地规划自己的罗马尼亚之旅,节省时间和精力,同时也能更好地享受旅行的乐趣。

本项目不仅为旅行者提供了便利,也可以作为学习图论算法的教学工具,帮助学生更好地理解和应用最短路径算法。通过这个项目,我们希望能够为旅行者和学生们带来更多的便利和启发,促进旅游业和教育的发展。

10.5.2  路径网络图

图在路径规划中扮演着至关重要的角色,它提供了建模、求解和优化路径规划问题的基础,并支持多种场景下的路径规划需求。在本项目中,文件graph.h扮演了图类的角色,它起到了如下所示的作用。

  1. 定义图类:在文件graph.h中定义了一个名为 graph 的类,该类用于表示图数据结构。图类通过邻接表的方式存储图的结构,使用哈希表(unordered_map)来存储节点及其相邻节点的关系,以及它们之间的边的权重。
  2. 实现图的基本操作:类graph提供了一系列方法来执行图的基本操作,包括添加边(addEdge)、打印图结构(printGraph)以及执行最短路径搜索(uniformCostSearch)等。
  3. 封装最短路径搜索算法:在类graph中,最短路径搜索算法被封装在 uniformCostSearch 方法中。这个方法利用了图的结构和最小堆优先队列来实现 Uniform Cost Search(统一代价搜索)算法,用于在图中查找两个节点之间的最短路径。
  4. 提供图的信息和操作接口:通过类graph,可以方便地创建图对象,并对图进行操作和查询。它为项目中其他部分提供了图数据结构的抽象化表示,使得整个项目更易于理解和维护。

文件graph.h的具体实现流程如下所示。

(1)导入需要的头文件,此处需要注意的是,#ifndef GRAPH_H_ 和 #define GRAPH_H_ 是 C/C++ 中的预处理器指令,用于防止头文件被多次包含导致的重定义错误。这样,当头文件被多次引用时,只有第一次引用会生效,后续的引用都会被忽略,从而避免了重定义错误。

#ifndef GRAPH_H_
#define GRAPH_H_
#include<iostream>
#include<unordered_map>
#include<map>
#include<list>
#include<vector>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>

using namespace std;

(2)类 graph 是一个图类,用于表示图数据结构并提供了一些图的基本操作,例如添加边、打印图信息、执行统一成本搜索(Uniform Cost Search)等功能。类 graph的成员包括:

  1. adjList:使用哈希表表示图的邻接列表,存储了图中每个顶点的相邻顶点及其边的权重。
  2. V:表示图的顶点数。
  3. E:表示图的边数。

类 graph主要用于在图中执行路径规划任务,用户可以通过调用成员函数来构建图、执行路径搜索,并获取最短路径的信息。

class graph{

    unordered_map<string, list<pair<string,int>>> adjList;
    int V=0;
    int E=0;
    
    public:
        graph(int V)
        {
            this->V=V;
        };
        void addEdge(string, string, int);
        void uniformCostSearch(string, string);
        void printGraph();
};

(3)graph::addEdge(string start, string end, int weight) 是 graph 类的成员函数,用于向图中添加一条边。它接受如下所示的三个参数:

  1. start:表示边的起点。
  2. end:表示边的终点。
  3. weight:表示边的权重或距离。

函数graph::addEdge(string start, string end, int weight)的作用是将一条边从起点 start 连接到终点 end,并指定了这条边的权重。在图的邻接列表中,起点 start 对应的列表中会添加一个新的邻接顶点 end,并且指定它们之间的边的权重为 weight。同时,由于是无向图,所以也会在终点 end 对应的邻接列表中添加起点 start 作为邻接顶点,并设置相同的边权重。这个函数的实现将新的邻接顶点和权重信息添加到了图的邻接列表中,从而完成了图中边的添加操作。

void graph::addEdge(string start, string end, int weight){
    adjList[start].push_back(make_pair(end,weight));
    adjList[end].push_back(make_pair(start,weight));
    E++;
}

(4)函数graph::printGraph()用于打印输出图的邻接表表示,显示图中每个顶点的相邻顶点以及它们之间的边的权重。

void graph::printGraph(){
    cout<<"Number of Vertex: "<<V<<endl;
    cout<<"Number of Edges: "<<E<<endl<<endl;
    for(auto i=adjList.begin();i!=adjList.end();i++){
        cout<<i->first<<" -> ";
        for(auto j=i->second.begin();j!=i->second.end();j++){
            cout<<"("<<j->first<<","<<j->second<<") ";
        }
        cout<<endl;
    }
    cout<<endl;
}

(5)函数graph::uniformCostSearch(string start, string end)的功能是使用统一代价搜索(Uniform Cost Search)算法来寻找从起始城市到目标城市的最短路径。参数start表示起始城市的名称,参数end表示目标城市的名称。函数graph::uniformCostSearch(string start, string end)的实现步骤如下所示:

  1. 初始化一系列数据结构,包括用于记录已探索节点、节点距离、父节点关系的数据结构。
  2. 将起始城市加入优先队列(或堆),并将其标记为已探索。
  3. 不断从优先队列中弹出代价最小的节点,然后扩展该节点的相邻节点。
  4. 对于每个相邻节点,如果其尚未被探索或发现更短的路径到达它,则将其加入优先队列并更新相关信息。
  5. 当遇到目标城市或者队列为空时停止搜索。
  6. 如果找到目标城市,则回溯路径,并输出最短路径的信息。
  7. 如果找到了从起始城市到目标城市的路径,则输出最短路径的总距离以及路径上的所有城市名称。如果未找到路径,则输出提示信息表示未找到路径。
void graph::uniformCostSearch(string start, string end){
    unordered_map<string, bool> explored;   //keep track of explored nodes
    unordered_map<string, int> distance;    //distance from start to nodes
    unordered_map<string, string> parent;   //parent of nodes
    priority_queue<pair<string, int>, vector<pair<string, int>>, less<pair<string, int>>> frontier;  //keep track of nodes to be explored
    stack<string> child;        //To reverse the path
    
    frontier.push(make_pair(start, 0));
    explored[start]=true;
    distance[start]=0;
    parent[start]="";
    while(!frontier.empty()){
        string u=frontier.top().first;  //get the node with minimum distance
        frontier.pop();
        
        if(u==end){                     //Found goal (Base case)
            cout<<"Shortest path from "<<start<<" to "<<end<<" is: "<<distance[end]<<endl;
            cout<<"Path: ";
            while(parent[u]!=""){
                u=parent[u];
                child.push(u);  //reverse the path
            }
            while(!child.empty()){
                cout<<child.top()<<" -> ";
                child.pop();
            }
            cout<<end<<endl;
            return;
        }

        for(auto i=adjList[u].begin();i!=adjList[u].end();i++){
            if(!explored[i->first]){
                explored[i->first]=true;
                distance[i->first]=distance[u]+i->second;
                parent[i->first]=u;
                frontier.push(make_pair(i->first, distance[i->first]));
            }
            else if(distance[u]+i->second < distance[i->first]){
                distance[i->first]=distance[u]+i->second;
                parent[i->first]=u;
                frontier.push(make_pair(i->first, distance[i->first]));
            }
        }
    }
    cout<<"No path found"<<endl;
}

#endif /* GRAPH_H_ */

10.5.3  主程序

本项目的主程序是shortest_path.cpp,作为本项目的主程序入口,使用了文件graph.h中定义的图类graph来解决罗马尼亚城市之间的最短路径问题。具体功能包括:

  1. 创建一个图对象并初始化城市之间的道路及其距离。
  2. 打印出城市图的结构,包括顶点数量、边数量以及每个顶点的邻接顶点及对应的权重。
  3. 通过用户输入选择起始城市和目标城市。
  4. 调用图类中的统一代价搜索函数(uniformCostSearch)来寻找起始城市到目标城市的最短路径。
  5. 如果找到了路径,则输出最短路径的总距离以及路径上的所有城市名称;如果未找到路径,则输出提示信息表示未找到路径。
  6. 最后,等待用户按下任意键以退出程序。
#include <iostream>
#include<string>
#include<algorithm>
using namespace std;
#include "graph.h"

int main(){
        graph g(20);
        g.addEdge("Neamt", "Iasi", 87);
        g.addEdge("Iasi","Vaslui", 92);
        g.addEdge("Vaslui","Urziceni", 142);
        g.addEdge("Urziceni","Hirsova", 98);
        g.addEdge("Hirsova","Eforie", 86);
        g.addEdge("Urziceni","Bucharest", 85);
        g.addEdge("Bucharest","Giurgiu", 90);
        g.addEdge("Bucharest","Fagaras", 211);
        g.addEdge("Bucharest","Pitesti", 101);
        g.addEdge("Pitesti","Craiova", 138);
        g.addEdge("Pitesti","Rimnicu Vilcea", 97);
        g.addEdge("Craiova","Rimnicu Vilcea", 146);
        g.addEdge("Rimnicu Vilcea","Sibiu", 80);
        g.addEdge("Sibiu","Fagaras", 99);
        g.addEdge("Sibiu","Oradea", 151);
        g.addEdge("Oradea","Zerind", 71);
        g.addEdge("Zerind","Arad", 75);
        g.addEdge("Arad","Timisoara", 118);
        g.addEdge("Timisoara","Lugoj",111);
        g.addEdge("Lugoj","Mehadia",70);
        g.addEdge("Mehadia","Dobreta",75);
        g.addEdge("Dobreta","Craiova",120);
        g.addEdge("Arad","Sibiu", 140);

        g.printGraph();

        string start, end;
        cout<<"Enter start city: ";
        cin>>start;
        start[0]=toupper(start[0]);
        
        cout<<"Enter end city: ";
        cin>>end;
        end[0]=toupper(end[0]);

        g.uniformCostSearch(start, end);
        system("pause");
        return 0;
}

执行后会先输出显示了图的结构,包括了顶点数量和边数量,以及每个顶点的邻接顶点及对应的权重。其中,每一行以城市名称作为起点,后面跟随着该城市可到达的目标城市及其权重。

Number of Vertex: 20
Number of Edges: 23

Dobreta -> (Mehadia,75) (Craiova,120)
Arad -> (Zerind,75) (Timisoara,118) (Sibiu,140)
Zerind -> (Oradea,71) (Arad,75)
Rimnicu Vilcea -> (Pitesti,97) (Craiova,146) (Sibiu,80)
Neamt -> (Iasi,87)
Bucharest -> (Urziceni,85) (Giurgiu,90) (Fagaras,211) (Pitesti,101)
Mehadia -> (Lugoj,70) (Dobreta,75)
Iasi -> (Neamt,87) (Vaslui,92)
Fagaras -> (Bucharest,211) (Sibiu,99)
Giurgiu -> (Bucharest,90)
Hirsova -> (Urziceni,98) (Eforie,86)
Urziceni -> (Vaslui,142) (Hirsova,98) (Bucharest,85)
Eforie -> (Hirsova,86)
Vaslui -> (Iasi,92) (Urziceni,142)
Pitesti -> (Bucharest,101) (Craiova,138) (Rimnicu Vilcea,97)
Lugoj -> (Timisoara,111) (Mehadia,70)
Timisoara -> (Arad,118) (Lugoj,111)
Oradea -> (Sibiu,151) (Zerind,71)
Sibiu -> (Rimnicu Vilcea,80) (Fagaras,99) (Oradea,151) (Arad,140)
Craiova -> (Pitesti,138) (Rimnicu Vilcea,146) (Dobreta,120)

Enter start city:

接下来程序等待用户输入起始城市名称,例如分别输入Bucharest(出发地)和Iasi(目的地):

Enter start city: Bucharest
Enter end city: Iasi

按下回车键后程序将执行最短路径搜索算法,并输出最短路径的长度以及路径经过的城市。

Shortest path from Bucharest to Iasi is: 319
Path: Bucharest -> Urziceni -> Vaslui -> Iasi

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值