数据结构 07-图6 旅游规划 (25 分)

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:

输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2N500)是城市的个数,顺便假设城市的编号为0~(N1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。

输出格式:

在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
 

输出样例:

3 40

 

 

 

 

Dijkstra算法 参考这篇文章,讲的很通俗 https://wiki.jikexueyuan.com/project/easy-learn-algorithm/dijkstra.html

//Dijkstra算法核心语句
//inf为最大值 题目给的是不大于500 这里随便给一个大于500的值就可以
//还需要一个辅助的数组visited[n]用于标记是否遍历过结点

for(i=0;i<n;i++)
{
    //找到离1号顶点最近的顶点
    min=inf;
    for(j=0;j<n;j++)
    {
        if(visited[j]==0 && dis[j]<min)
        {
            min=dis[j];
            u=j;
        }
    }
    visited[u]=1;
    for(v=0;v<n;v++)
    {
        if(e[u][v]<inf)
        {
            if(dis[v]>dis[u]+e[u][v])
                dis[v]=dis[u]+e[u][v];
        }
    }
}

 

 

 

#include <iostream>
#include <vector>
using namespace std;
class vertexNode{
public:
    int s;//源城市
    int d;//目的城市
    int weight;//路程长 权值
    int charge;//收费
    vertexNode()=default;
    vertexNode(int s_,int d_,int w_,int c_):s{s_},d{d_},weight{w_},charge{c_}{};
};
class AdjacencyLinkGraphic{
public:
    vector<vector<vertexNode*>> vertexs;//二维数组, 存的值是结点 包含该点的路径和收费 vertexs[i][j] i是起点 j是终点
    int cityNum{0};
    int highwayNum{0};
    int s;//出发城市
    int d;//目的城市
    AdjacencyLinkGraphic()=default;
    AdjacencyLinkGraphic(int n_,int m_,int s_,int d_):cityNum{n_},highwayNum{m_},s{s_},d{d_}{};
    void build(){
        vertexs=vector<vector<vertexNode*>>(cityNum,vector<vertexNode*>(cityNum,nullptr));
        int s,d,w,c;
        for(int i=0;i<highwayNum;i++){
            scanf("%d %d %d %d",&s,&d,&w,&c);
            vertexs[s][d]=new vertexNode{s,d,w,c};
            vertexs[d][s]=new vertexNode{d,s,w,c};
        }
    }
    void dijkstra(){
        vector<int> visited(cityNum);
        visited[s]=1;
        int u;//起点 的 未访问的 最小权值的 邻接点
        // 先将s的访问位置为1,
        // 1.找到u 然后将u的访问位置为1
        // 2.先由起点的最小权值邻接点 u 开始, 寻找起点s 经由 u 到u的邻接点 j 的总权值是否小于 s到j的权值
        // 3.如果经由 s 经由 u 到 j 的的路径权值小于s到j的权值 ,就更新s到j的权值为 (s到u的权值)+(u到j的权值)
        // 循环直到s的邻接点全部遍历完毕,这时就得到了s到任意连通点的最小路径长 和 对应的收费
        //直接输出 vertexs[s][d]的路径长 和 收费
        for(int i=0;i<cityNum;i++){
            int min=999999;
            for(int j=0;j<cityNum;j++){
                if( vertexs[s][j] && !visited[j] && vertexs[s][j]->weight < min){
                    min=  vertexs[s][j]->weight;
                    u = j;
                }
            }
            visited[u]=1;
            for(int j=0; j<cityNum; j++){
                if( vertexs[u][j] && vertexs[u][j]->weight <= 99999 ){
                    if( vertexs[u][j] && vertexs[s][u] && vertexs[s][j] ){//确认为连通点
                        if(vertexs[s][j]->weight == vertexs[s][u]->weight + vertexs[u][j]->weight){
                            if(vertexs[s][j]->charge > vertexs[s][u]->charge + vertexs[u][j]->charge)
                            vertexs[s][j]->charge=vertexs[s][u]->charge+vertexs[u][j]->charge;
                        }else if(vertexs[s][j]->weight > vertexs[s][u]->weight + vertexs[u][j]->weight){
                            //更新由s到j的最小权值和对应的路费
                            vertexs[s][j]->weight = vertexs[s][u]->weight + vertexs[u][j]->weight;
                            vertexs[s][j]->charge = vertexs[s][u]->charge + vertexs[u][j]->charge;
                        }
                    }
                }
            }
        }
        cout << vertexs[s][d]->weight <<" "<< vertexs[s][d]->charge<<endl;
    }
};
int main(){
    int n,m,s,d;
    cin >> n >> m >> s >> d ;
    AdjacencyLinkGraphic ALG{n,m,s,d};
    ALG.build();
    ALG.dijkstra();
    return 0;
}

 

posted @ 2021-05-24 00:28  keiiha  阅读(207)  评论(0编辑  收藏  举报