7-10 旅游规划 (25 分)

7-10 旅游规划 (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算法

1.定义概览

Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。

问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)

 

2.算法描述

1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

(1) 初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为"起点s到该顶点的距离"[例如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。

(2) 从U中选出"距离最短的顶点k",并将顶点k加入到S中;同时,从U中移除顶点k。

(3) 更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。

(4) 重复步骤(2)和(3),直到遍历完所有顶点。
#include<iostream>
#include<stdio.h>
using namespace std;
//距离表
struct
{
    int visit;
    int len;
    int cost;
}Visit[510];
//路线图
struct
{
    int len;
    int cost;
}Graph[510][510];
//初始化路线图,长度和过路费全初始化为999,相当于无穷
void InitGraph(int N)
{
    for(int i=0; i<=N; i++)
        for(int j=0; j<=N; j++){
            Graph[i][j].len = 999;
            Graph[i][j].cost = 999;
        }
}
//根据输入的路线图初始化距离表
//并且初始化源地到源地的距离和路费均为0
void InitVisit(int N, int S)
{
    for(int i=0; i<=N; i++){
        Visit[i].visit = 0;
        Visit[i].len = Graph[i][S].len;
        Visit[i].cost = Graph[i][S].cost;
    }
    Visit[S].visit = 1;
    Visit[S].cost = 0;
    Visit[S].len = 0;
}
//利用Dijkstra(迪杰斯特拉)算法计算源地到各地的距离最短
int DKS(int N, int S)
{
    //循环 N-1 次找到这N-1个点到源点的距离最短
    for(int j=1; j<N; j++){
        //先找到一个距离最短的点
        int MinPoint=N;//第N+1个点的距离已设置为999,相当于无穷
        for(int i=0; i<N; i++){
            if(!Visit[i].visit&&Visit[i].len<Visit[MinPoint].len){
                MinPoint = i;
            }
        }
        if(MinPoint == N)//没找到最短点,也就是完成循环,退出,可省略
            break;
        Visit[MinPoint].visit = 1;
        for(int i=0; i<N; i++){
               if(!Visit[i].visit){
                  //原点->中继点->终点 < 原点->终点,更新最短距离
                  if(Visit[i].len>Visit[MinPoint].len+Graph[i][MinPoint].len){
                    Visit[i].len = Visit[MinPoint].len+Graph[i][MinPoint].len;
                    Visit[i].cost = Visit[MinPoint].cost+Graph[i][MinPoint].cost;
                  }
                  //距离相同找花费更小的
                  if(Visit[i].len==Visit[MinPoint].len+Graph[i][MinPoint].len){
                    if(Visit[i].cost>Visit[MinPoint].cost+Graph[i][MinPoint].cost)
                    Visit[i].cost=Visit[MinPoint].cost+Graph[i][MinPoint].cost;
                  }
               }
        }
    }

}
int main()
{
    int N, M, S, D;
    cin>>N>>M>>S>>D;
    InitGraph(N);
    int c1, c2, l, m;
    for(int i=0; i<M; i++){
        cin>>c1>>c2>>l>>m;
        Graph[c1][c2].len = l;
        Graph[c1][c2].cost = m;
        Graph[c2][c1].len = l;
        Graph[c2][c1].cost = m;
    }
    InitVisit(N, S);
    DKS(N, S);
    cout<<Visit[D].len<<" "<<Visit[D].cost;
}
原文地址:https://www.cnblogs.com/Jie-Fei/p/9873419.html