L2-001. 紧急救援 (Dijkstra算法打印路径)

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

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2<=N<=500)是城市的个数,顺便假设城市的编号为0~(N-1);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 #include<stdio.h>
  2 #include<math.h>
  3 #include<stdlib.h>
  4 
  5 #define MAX 502
  6 #define INFI 9999999
  7 
  8 int G[MAX][MAX],nv,ne,c1,c2; //图,结点数,边数,起点,终点
  9 int know[MAX];              //访问标记
 10 int distance[MAX];          //距离
 11 int num[MAX];               //最短路径条数
 12 int weight[MAX];           //每个点的权值
 13 int w[MAX];                //最短路径上的点权值总和
 14 int pre[MAX];              //存放每个结点前一个结点
 15 void printPath( int v);
 16 void CreateGraph();
 17 void Dijkstra( );
 18 int main()
 19 {
 20     int i;
 21     scanf("%d%d%d%d",&nv,&ne,&c1,&c2);
 22     for( i=0; i<nv; i++)
 23         scanf("%d",&weight[i]);
 24     CreateGraph();
 25     Dijkstra();
 26     printf("%d %d\n",num[c2],w[c2]);
 27     printPath(c2);
 28     return 0;
 29 }
 30 
 31 void CreateGraph()
 32 {
 33     int i,j;
 34     int v1,v2;
 35     int dn;
 36     for( i=0; i<nv; i++)
 37         for( j=0; j<nv; j++)
 38             G[i][j]=INFI;
 39     for( i=0; i<ne; i++)
 40     {
 41         scanf("%d%d%d",&v1,&v2,&dn);
 42         G[v1][v2]=G[v2][v1]=dn;  //无向图
 43     }
 44 }
 45 void Dijkstra( )
 46 {
 47     int i,j,k;
 48     int min;
 49     for( i=0; i<nv; i++)
 50     {
 51         know[i]=0;
 52         distance[i]=G[c1][i];  //更新起点到所有顶点的距离
 53     }
 54     distance[c1]=0;           //起点到起点的距离为0
 55     w[c1]=weight[c1];
 56     num[c1]=1;
 57     for( i=1; i<nv; i++)
 58     {
 59         k=-1;
 60         min = INFI;
 61         for( j=0; j<nv; j++)
 62         {
 63             if( !know[j] && distance[j]<min)
 64             {
 65                 k=j;
 66                 min = distance[j];
 67             }
 68         }
 69         if( k==-1) break;
 70         know[k]=1;  //寻找到最短的距离,标记该点
 71         for( j=0; j<nv; j++)
 72         {
 73             if( !know[j] && min+G[k][j]<distance[j])  //更新距离
 74             {
 75                 distance[j] = min+G[k][j];
 76                 num[j] = num[k];
 77                 w[j] = w[k] + weight[j];
 78                 pre[j]=k;
 79             }
 80             else if( !know[j] && min+G[k][j]==distance[j])
 81             {
 82                 num[j]=num[j]+num[k];
 83                 if( w[k]+weight[j]>w[j])
 84                 {
 85                     w[j]=w[k]+weight[j];
 86                     pre[j]=k;
 87                 }
 88             }
 89         }
 90     }
 91 }
 92 
 93 void printPath( int v)  //递归打印路径
 94 {
 95     if( v==c1){
 96         printf("%d",v);
 97         return;
 98     }
 99     printPath( pre[v]);
100     printf(" %d",v);
101 }

 

posted @ 2018-03-10 11:01  yuxiaoba  阅读(304)  评论(0编辑  收藏  举报