PTA-数据结构 Dijkstra 城市间紧急救援

城市间紧急救援(25 分)

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2N500)是城市的个数,顺便假设城市的编号为0 ~ (N1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

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

输出样例:

2 60
0 1 3



代码及分析如下:
  1 /*
  2 
  3 目标:
  4 求最短路径长度和条数以及最短路径下的最多救援队数。(优先选择距离最短的路径,距离相同考虑救援队数量)
  5 代码解释:
  6 Way数组:Way【i】从出发点到i点的最短路径的数量
  7 Sum数组:Sum【i】从出发点到i点的一条或多条最短路径下的救援队数量最多的路径的救援队数量
  8 Peo数组:Peo【i】代表下表为i的点的初始救援队个数
  9 Move数组:Move【i】若为true代表小标为i的点已经被访问过了,为false则没有;
 10 Dist数组:Dist【i】代表从出发点到i点的最短距离
 11 思路:
 12 基本的最短路问题(这里选择迪杰斯特拉,注意它不能解决负权边问题)
 13 除此之外为了解决最短路径条数和最短路下的最大救援队数量引入Way数组和Sum数组
 14     递推公式
 15     Way【i】=ΣWay【j】(j为使得Dist【i】最小的i点的前驱,可能有多个),显然边界条件Way【s】=1(s为出发点);
 16     Sum【i】= Sum【j】+Peo【i】(j为最短路上i的前驱)
 17 */
 18 #include <iostream>
 19 #include <stdio.h>
 20 #include <stdlib.h>
 21 using namespace std;
 22 #define Max 500
 23 #define Sky 99999  //表示两点之间没有路径时的距离
 24 int distances[Max][Max],Top,Start,End,Edge;  //分别为 两城市间距离的二维数组 城市个数 起点 终点 边数
 25 int Dist[Max],Move[Max],Peo[Max],Sum[Max],Way[Max]; 
 26 void Dis()
 27 {
 28 int i,j;
 29 //初始化边界条件
 30     for(i=0;i<Top;i++)
 31     {
 32         Dist[i]=distances[Start][i];  //把最短距离初始化为起点到该点的直接距离
 33         Move[i]=false;  //每个点初始化为都没有访问
 34     }
 35     Dist[Start]=0;  //起点到本身距离为零
 36     Move[Start]=true;  //起点已经被访问
 37     Sum[Start]=Peo[Start];  //团队数仅为起点团队数
 38     Way[Start]=1;  //路径条数为1
 39 
 40     for(i=1;i<=Top-1;i++)  //除了起点还要循环top-1 次才能完成所有定点的访问
 41     {
 42         int minw=Sky;  //保存距离出发点最近的点距离出发点的距离,初始化为最大
 43         int k; //保存该点的编号
 44         for(j=0;j<Top;j++)//遍历每一个顶点
 45         {
 46             if(!Move[j])  //j没有被访问的话
 47             {
 48                 if(minw>Dist[j])//如果找到距离出发点更近的点,更新minw和k
 49                 {
 50                     minw=Dist[j];
 51                     k=j;
 52                 }
 53             }
 54         }
 55 
 56         Move[k]=true;  //更新过的k顶点处理完毕 标记数组为true
 57 
 58         for(j=0;j<Top;j++)//遍历每一个顶点
 59         {
 60             if(!Move[j])//如果没有访问(处理完毕)
 61             {
 62                 if(Dist[j]==Dist[k]+distances[k][j])/*如果从起点到下标j点的距离等于从起点先到k再到j的距离*/
 63                 {
 64                     Way[j]+=Way[k];//加和
 65                     if(Sum[j]<Sum[k]+Peo[j])//路径距离相同时,团队数更多
 66                     {
 67                         Sum[j]=Sum[k]+Peo[j];//团队数更新
 68                     }
 69                 }
 70                 if(Dist[j]>Dist[k]+distances[k][j])/* 如果从起点到下标j点的距离等于从起点先到k再到j的距离*/
 71                 {
 72                     Dist[j]=Dist[k]+distances[k][j];
 73                     Sum[j]=Sum[k]+Peo[j];
 74                     Way[j]=Way[k];
 75                 }
 76 
 77             }
 78         }
 79     }
 80 }
 81 void Dfs(int end,int Sump)
 82 {
 83     if(end==Start)//边界条件 
 84     {
 85         return;
 86     }
 87     for(int j=0;j<Top;j++)//遍历每一个顶点
 88     {
 89         if(Sump-Peo[end]==Sum[j] && Dist[end]-distances[end][j]==Dist[j])/*寻找当前点的前驱点*/
 90         {
 91            Dfs(j,Sum[j]);
 92            cout<<j<<"";
 93         }
 94     }
 95 
 96 }
 97 int main( )
 98 {
 99      cin>>Top>>Edge>>Start>>End;
100      int i,j;
101      for(i=0;i<Top;i++)
102      for(j=0;j<Top;j++)
103      distances[i][j]=Sky;
104 
105      for(i=0;i<Top;i++)
106      {
107          scanf("%d",&Peo[i]); 
108      }
109     
110      for(i=0;i<Edge;i++)
111      {
112          int x,y,z;
113          scanf("%d%d%d",&x,&y,&z);
114          distances[x][y]=distances[y][x]=z;//存入直接相连城市间的距离z
115      }
116      Dis();
117      cout<<Way[End]<<""<<Sum[End]<<endl;
118 
119      Dfs(End,Sum[End]); 
120      cout<<End<<endl;
121 
122 
123     return 0;
124 }

 

坚持不懈地努力才能成为大神!
posted @ 2017-11-07 22:54  己平事  阅读(2937)  评论(0编辑  收藏  举报