• 最短路径:Dijkstra和Floyd


    目录

    Dijkstra的基本思路与实现

    记录最短路径:利用前驱数组pre

    增加第二标准来决定最短路径

    给每条边再增加一个边权

    给每个点增加一个点权

    直接问有多少条最短路径

    习题

    PAT A1003 Emergency

    PAT A1030 Travel Plan

    Floyd算法


    Dijkstra的基本思路与实现

    设置S存放已被访问的结点,然后执行n次以下步骤,n为节点数目

    1. 每次从集合V-S中选择与起点s的最短距离最小的一个顶点(记为u),访问并加入集合S
    2. 令顶点u为中介点,优化起点s与所有从u能到达的顶点v之间的最短距离

    实现:
    ①集合S可以用一个bool数组vis[]来实现

    • 当vis[i]==true时表示顶点Vi已被访问
    • 当vis[i]==false表示顶点Vi未被访问

     ②令int数组d[]表示起点s到达顶点Vi的最短距离,初始时除了起点s的d[s]赋值为0,其余顶点都
    复制为一个很大的数

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. const int MAXV = 1000;//最大顶点数
    7. const int INF = 100000000;//设INF为一个很大的数
    8. int n, m, s;
    9. int G[MAXV][MAXV];//n为顶点数,
    10. int d[MAXV];//起点到达各点的最短路径长度
    11. bool vis[MAXV] = { false };//标记数组,true为一访问,
    12. void Dijkstra(int s) {
    13. fill(d, d + MAXV, INF);
    14. d[s] = 0;//起点s到达自身的距离为0
    15. for (int i = 0; i < n; i++) {//循环n次
    16. int u = -1, MIN = INF;//u使d[u]最小,MIN存放最小的d[u]
    17. for (int j = 0; j < n; j++) {
    18. if (vis[j] == false && d[j] < MIN) {
    19. u = j;
    20. MIN = d[j];
    21. }
    22. }
    23. //找不到小于INF的d[u],说明剩下的顶点和起点s不连通
    24. if (u == -1)return;
    25. vis[u] = true;//标记u为已访问
    26. for (int v = 0; v < n; v++) {
    27. //如果v未访问 && u能到达v && 以u为中介可以使d[v]更优
    28. if (vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]) {
    29. d[v] = d[u] + G[u][v];
    30. }
    31. }
    32. }
    33. }
    34. int main() {
    35. int u, v, w;
    36. cin >> n >> m >> s;
    37. fill(G[0], G[0] + MAXV * MAXV, INF);
    38. for (int i = 0; i < m; i++) {
    39. cin >> u >> v >> w;
    40. G[u][v] = w;
    41. }
    42. Dijkstra(s);
    43. for (int i = 0; i < n; i++) {
    44. printf("%d ", d[i]);
    45. }
    46. return 0;
    47. }

     

    记录最短路径:利用前驱数组pre

    1. #include
    2. using namespace std;
    3. const int MAXV = 1000;//最大顶点数
    4. const int INF = 100000000;//设INF为一个很大的数
    5. int n;
    6. int G[MAXV][MAXV];
    7. int d[MAXV];
    8. int pre[MAXV];
    9. bool vis[MAXV] = { false };
    10. void Dijkstra(int s) {
    11. fill(d, d + MAXV, INF);
    12. d[s] = 0;
    13. for (int i = 0; i < n; i++)pre[i] = i;//初始状态设每个点的前驱为自身
    14. for (int i = 0; i < n; i++) {
    15. int u = -1, MIN = INF;
    16. for (int j = 0; j < n; j++) {
    17. if (vis[j] == false && d[j] < MIN) {
    18. u = j;
    19. MIN = d[j];
    20. }
    21. }
    22. if (u == -1)return;
    23. vis[u] = true;
    24. for (int v = 0; v < n; v++) {
    25. if (vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]) {
    26. d[v] = d[u] + G[u][v];
    27. pre[v] = u;//记录v的前去顶点是u
    28. }
    29. }
    30. }
    31. }
    32. void dfs(int s, int v) {
    33. if (v == s) {
    34. cout << s << endl;
    35. return;
    36. }
    37. dfs(s, pre[v]);
    38. cout << v << endl;
    39. }

    增加第二标准来决定最短路径

    对于这类题目,只需要新增加一个数组来存放新增的边权或点权或最短路径条数,然后再Dijkstra中修改优化d[v]的那个步骤即可,其他部分不需要改动

    给每条边再增加一个边权

    比如说花费,在最短路径有多条时选择花费最小的.

    用cost[u][v]表示u到v的花费,并增加一个数组c[],令从起点s到达顶点u的最少花费为c[u],初始化时只有c[s]为0,其余c[u]均为INF,这样就可以在d[u[+G[u][v]

    而当d[u]+G[u][v]==d[v]时,且c[u]+cost[u][v]]:

    1. for (int v = 0; v < n; v++) {
    2. if (vis[v] == false && G[u][v] != INF) {
    3. if (d[u] + G[u][v] < d[v]) {
    4. d[v] = d[u] + G[u][v];
    5. c[v] = c[u] + cost[u][v];
    6. }
    7. else if ((d[u] + G[u][v] == d[v] && c[u] + cost[u][v] < c[v]) {
    8. c[v]=c[u]+cost[u][v];
    9. }
    10. }
    11. }

    给每个点增加一个点权

    比如说每个城市收集到的物资,在最短路径有多条时选择收集物资最多的

    用weight[u]表示城市u中的物资数目,并增加一个数组w[],令从起点s到达顶点u可以收集到的最大物资为w[u],初始化时只有w[s]为weight[s],其余w[u]均为0,d[u[+G[u][v]

    而当d[u]+G[u][v]==d[v]时,且w[u]+weight[v]>w[v]时更新w[v]: 

    1. for (int v = 0; v < n; v++) {
    2. if (vis[v] == false && G[u][v] != INF) {
    3. if (d[u] + G[u][v] < d[v]) {
    4. d[v] = d[u] + G[u][v];
    5. w[v] = w[u] + weight[v];
    6. }
    7. else if ((d[u] + G[u][v] == d[v] && w[u] + weight[v] > w[v]) {
    8. w[v]=w[u]+weight[v];
    9. }
    10. }
    11. }

    直接问有多少条最短路径

    只需要增加一个数组num[],令从起点s到达顶点u的最短路径条数为num[u],初始化时只有nums[s]为1,其余num[u]为0,这样就可以在d[u]+G[u][v]

    而当d[u]+G[u][v]==d[v]时,将num[u]加到num[v]上:

    1. for (int v = 0; v < n; v++) {
    2. if (vis[v] == false && G[u][v] != INF) {
    3. if (d[u] + G[u][v] < d[v]) {
    4. d[v] = d[u] + G[u][v];
    5. num[v] = num[u];
    6. }
    7. else if (d[u] + G[u][v] == d[v]) {
    8. num[v] += num[u];
    9. }
    10. }
    11. }

    习题

    PAT A1003 Emergency

    题目详情 - 1003 Emergency (pintia.cn)

    1003 Emergency

    分数 25

    作者 CHEN, Yue 单位 浙江大学

    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, C1​ and C2​ - 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 c1​, c2​ 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 C1​ to C2​.

    Output Specification:

    For each test case, print in one line two numbers: the number of different shortest paths between C1​ and C2​, 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.

    Sample Input:

    1. 5 6 0 2
    2. 1 2 1 5 3
    3. 0 1 1
    4. 0 2 2
    5. 0 3 1
    6. 1 2 1
    7. 2 4 1
    8. 3 4 1

    Sample Output:

    2 4
    

    代码长度限制 16 KB

    时间限制 400 ms

    内存限制 64 MB

    题意:给N个城市,M条无向边。每个城市有一定数目的救援小组,所有边的边权已知。现在给出起点和重点,求从起点到终点的最短路径条数以及最短路径上救援小组的数目之和,如果有多条最短路径,则输出数目之和最大的

    1. #include
    2. using namespace std;
    3. const int INF = 100000000;
    4. const int MAXV = 505;
    5. int n, m, st, ed;
    6. int G[MAXV][MAXV], weight[MAXV];
    7. bool vis[MAXV] = { false };
    8. int d[MAXV], w[MAXV], num[MAXV];
    9. void Dijkstra(int s) {
    10. fill(d, d + MAXV, INF);
    11. fill(num, num + MAXV, 0);
    12. fill(w, w + MAXV, 0);
    13. d[s] = 0;
    14. w[s] = weight[s];
    15. num[s] = 1;
    16. for (int i = 0; i < n; i++) {
    17. int u = -1, MIN = INF;
    18. for (int j = 0; j < n; j++) {
    19. if (vis[j] == false && d[j] < MIN) {
    20. u = j;
    21. MIN = d[j];
    22. }
    23. }
    24. if (u == -1)return;
    25. vis[u] = true;
    26. for (int v = 0; v < n; v++) {
    27. if (vis[v] == false && G[u][v]!=INF) {
    28. if (d[u] + G[u][v] < d[v]) {
    29. d[v] = d[u] + G[u][v];
    30. w[v] = w[u] + weight[v];
    31. num[v] = num[u];
    32. }
    33. else if (d[u] + G[u][v] == d[v]) {
    34. if (w[u] + weight[v] > w[v]) {
    35. w[v] = w[u] + weight[v];
    36. }
    37. num[v] += num[u];
    38. }
    39. }
    40. }
    41. }
    42. }
    43. int main() {
    44. cin >> n >> m >> st >> ed;
    45. for (int i = 0; i < n; i++) {
    46. cin >> weight[i];
    47. }
    48. fill(G[0], G[0] + MAXV * MAXV, INF);
    49. for (int i = 0; i < m; i++) {
    50. int u, v, w;
    51. cin >> u >> v >> w;
    52. G[u][v] = G[v][u] = w;
    53. }
    54. Dijkstra(st);
    55. cout << num[ed] << " " << w[ed];
    56. return 0;
    57. }

    PAT A1030 Travel Plan

    1030 Travel Plan

    分数 30

    作者 CHEN, Yue  单位 浙江大学

    A traveler's map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

    Input Specification:

    Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

    City1 City2 Distance Cost
    

    where the numbers are all integers no more than 500, and are separated by a space.

    Output Specification:

    For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

    Sample Input:

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

    Sample Output:

    0 2 3 3 40
    

    代码长度限制 16 KB

    时间限制 400 ms

    内存限制 64 MB

    题意:有N个城市,M条道路,并给出M条道路的距离属性和花费,给定起点S和目的地D,求从起点S到D的最短路径、最短距离和花费,如果有多条最短路径,选择花费最小的那条

    1. #include
    2. using namespace std;
    3. const int INF = 100000000;
    4. const int MAXV = 505;
    5. int n, m, st, ed;
    6. int G[MAXV][MAXV], cost[MAXV][MAXV];
    7. int d[MAXV], c[MAXV], pre[MAXV];
    8. bool vis[MAXV] = { false };
    9. void Dijkstra(int s) {
    10. fill(d, d + MAXV, INF);
    11. fill(c, c + MAXV, 0);
    12. for (int i = 0; i < n; i++)pre[i] = i;
    13. d[s] = 0;
    14. c[s] = 0;
    15. for (int i = 0; i < n; i++) {
    16. int u = -1, MIN = INF;
    17. for (int j = 0; j < n; j++) {
    18. if (vis[j] == false && d[j] < MIN) {
    19. u = j;
    20. MIN = d[j];
    21. }
    22. }
    23. if (u == -1)return;
    24. vis[u] = true;
    25. for (int v = 0; v < n; v++) {
    26. if (vis[v] == false && G[u][v] != INF) {
    27. if (d[u] + G[u][v] < d[v]) {
    28. d[v] = d[u] + G[u][v];
    29. c[v] = c[u] + cost[u][v];
    30. pre[v] = u;
    31. }
    32. else if (d[u] + G[u][v] == d[v] && c[u] + cost[u][v] < c[v]) {
    33. c[v] = c[u] + cost[u][v];
    34. pre[v] = u;
    35. }
    36. }
    37. }
    38. }
    39. }
    40. void dfs(int v) {
    41. if (v == st) {
    42. cout << v << " ";
    43. return;
    44. }
    45. dfs(pre[v]);
    46. cout << v << " ";
    47. }
    48. int main() {
    49. cin >> n >> m >> st >> ed;
    50. fill(G[0], G[0] + MAXV * MAXV, INF);
    51. for (int i = 0; i < m; i++) {
    52. int c1, c2, dis, co;
    53. cin >> c1 >> c2 >> dis >> co;
    54. G[c1][c2] = G[c2][c1] = dis;
    55. cost[c1][c2] = cost[c2][c1] = co;
    56. }
    57. Dijkstra(st);
    58. dfs(ed);
    59. cout << d[ed] << " " << c[ed];
    60. return 0;
    61. }

    Floyd算法

    floyd的算法时间复杂度为O(n^3),故顶点数n不能太大,一般不超过200

    如果存在顶点k,使得以k作为中介点时顶点i和顶点j的当前最短距离缩短,则使用顶点k作为i和j的中介点。即当dis[i][k]+dis[k][j]

    1. #include
    2. #include
    3. using namespace std;
    4. const int INF = 100000000;
    5. const int MAXV = 200;
    6. int n, m;
    7. int dis[MAXV][MAXV];
    8. void Floyd() {
    9. for (int k = 0; k < n; k++) {
    10. for (int i = 0; i < n; i++) {
    11. for (int j = 0; j < n; j++) {
    12. if (dis[i][k] != INF && dis[k][j] != INF && dis[i][k] + dis[k][j] < dis[i][j]) {
    13. dis[i][j] = dis[i][k] + dis[k][j];
    14. }
    15. }
    16. }
    17. }
    18. }
    19. int main() {
    20. int u, v, w;
    21. fill(dis[0], dis[0] + MAXV * MAXV, INF);
    22. cin >> u >> v >> w;
    23. for (int i = 0; i < n; i++)dis[i][i] = 0;
    24. for (int i = 0; i < n; i++) {
    25. cin >> u >> v >> w;
    26. dis[u][v] = w;
    27. }
    28. Floyd();
    29. for (int i = 0; i < n; i++) {
    30. for (int j = 0; j < n; j++) {
    31. cout << dis[i][j] << " ";
    32. }
    33. cout << endl;
    34. }
    35. return 0;
    36. }

  • 相关阅读:
    【Nginx】Windows平台下配置Nginx服务实现负载均衡
    8通道Pt100/Pt1000转RS-485/232,热电阻温度Modbus数据采集模块 WJ225
    聊聊日志聚类算法及其应用场景
    playwright 脚本调试
    c语言数据结构,你可能还不知道的顺序表
    win10打开VMware 16 pro里面的虚拟机就蓝屏怎么办
    中国生态功能保护区shp数据
    护士人文修养
    4.24总结
    Python入门系列(十一)一篇搞定python操作MySQL数据库
  • 原文地址:https://blog.csdn.net/Jason6620/article/details/126556448