【图】Dijkstra算法及其相关应用的C++详解

本文部分内容转载自:CSDN帖1

Dijkstra算法是一种用于计算最短路径的算法。

1.计算源点到各个顶点的最短距离

操作步骤

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),直到遍历完所有顶点。

例题:PAT甲级1003

1003 Emergency (25分)

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

作为城市的急救队长,你获得了一张城市的特殊地图,这张地图显示了几个不同城市的连线。上面标注了每个城市的急救队数量以及每条路的长度。
当有其他城市的急救电话打来的时候,你的工作就是带着你的人用最快路线赶到事发地点,同时,叫上越多人越好。

Input Specification:
输入说明:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C​1​​ and C​2​​ - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c​1​​, c​2​​ and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C​1​​ to C​2​​.

每个输入文件包含一个测试样例,在每个测试样例中,第一行包含四个正数:
第一个,N——(小于五百),那是城市的数量(城市的标号为0~N-1);
第二个,M——路的数量;
第三个,C1——你所在的城市标号(源点);
第四个,C2——你要救援的城市标号(终点)。

第二行包含N个正数,是每个城市的救援队数量;
第三行包含M组数,每一组为:路线出发城市,路线终点城市,路线长度;
此外,在目标城市和你所在的城市之间至少有一条路。

Output Specification:
输出说明:

For each test case, print in one line two numbers: the number of different shortest paths between C​1​​ and C​2​​, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

对于每一个测试样例,在一行中输出两个数:目标城市与你所在的城市之间的最短路径数量,还有你能集结的最多救援队数量。两个数之间用一个空格分隔,请保证在输出过程中没有多余的空格。

在这里插入图片描述人话题目描述:

共有 N个城市和M条路,已知边和点的权重,给出源点和终点,求两个城市之间的最短路径的数量以及最大点权,多条路径的时候选点权最大的值进行输出。

代码实现:

//这是柳神的代码,我只是添加了注释和说明
————变量解释————

变量 解释
n 城市数(点数)
m 路数(变数)
dis[i] 从源点出发到i点的最短路径长度
num[i] 从源点到i点的最短路径的条数
w[i] 从源点到i点的点权之和
e【】【】 两点之间边的权重
weight[] 点权
#include <iostream>
#include <algorithm>  //引入算法库
using namespace std;

//全局变量尽量设置为公用的 
int n, m, c1, c2;
int e[510][510], weight[510], dis[510], num[510], w[510];
bool visit[510];//不知道这个visit变量是什么意思:用来判定一个点是否被访问过
const int inf = 99999999;


int main() {
    
    
    scanf("%d%d%d%d", &n, &m, &c1, &c2);
    //输入点权
    for(int i = 0; i < n; i++)
        scanf("%d", &weight[i]);
    
    fill(e[0], e[0] + 510 * 510, inf);
    fill(dis, dis + 510, inf);
    
    //用户输入边权
    int a, b, c;
    for(int i = 0; i < m; i++) {
    
    
        scanf("%d%d%d", &a, &b, &c);
        e[a][b] = e[b][a] = c;
    }
    
    dis[c1] = 0;
    w[c1] = weight[c1];
    num[c1] = 1;
    
    //我不明白,但整个过程看起来像是在找源点
    for(int i = 0; i < n; i++) {
    
    
        int u = -1, minn = inf;
        for(int j = 0; j < n; j++) {
    
    
            if(visit[j] == false && dis[j] < minn) {
    
     //这个判定的意思是,j点还没有被访问过,而且这个点是可以通过源点访问到的
                u = j;
                minn = dis[j];
            }
        }
        if(u == -1) break;

         //开始Dijstra
        visit[u] = true;
        for(int v = 0; v < n; v++) {
    
    
            if(visit[v] == false && e[u][v] != inf) {
    
    
                if(dis[u] + e[u][v] < dis[v]) {
    
    
                    dis[v] = dis[u] + e[u][v];
                    num[v] = num[u];
                    w[v] = w[u] + weight[v];
                } else if(dis[u] + e[u][v] == dis[v]) {
    
    
                    num[v] = num[v] + num[u];
                    if(w[u] + weight[v] > w[v])
                        w[v] = w[u] + weight[v];
                }
            }
        }
    }
    printf("%d %d", num[c2], w[c2]);
    return 0;
}

总结

1)公用变量尽量不放在main里,放在main前面;

2)fill()函数的使用方法:

按照单元赋值,将一个区间的元素都赋同一个值
在头文件里面 #include

fill函数可以赋值任何,而且使用方法特别简便:

fill(first,last,val);

first 为容器的首迭代器,last为容器的末迭代器,val为将要替换的值。

int main()
{
int arr[10];
fill(arr, arr + 10, 2);
return 0;
}

猜你喜欢

转载自blog.csdn.net/Cambridge26/article/details/108939100