团体程序设计天梯赛-练习集 L2-001 紧急救援 (25 分)

时间:2023-02-13 11:53:51

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

输入格式:

输入第一行给出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 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <algorithm>
  6 #include <utility>
  7 #include <vector>
  8 #include <map>
  9 #include <queue>
 10 #include <stack>
 11 #include <cstdlib>
 12 #include <cmath>
 13 typedef long long ll;
 14 #define lowbit(x) (x&(-x))
 15 #define ls l,m,rt<<1
 16 #define rs m+1,r,rt<<1|1
 17 using namespace std;
 18 #define pi acos(-1)
 19 #define P pair<ll,ll>
 20 int n,m,s,d;
 21 const int N = 1e3+100;
 22 int pre[N],f[N][N],val[N],sval[N],dis[N],num[N];
 23 //pre[i]:i前面的点
 24 //sval[i]:到i时的所有最短路径里可以召集的最多的救援队数量
 25 //dis[i]:s 到i 的最短距离
 26 //num[i]:到i的最短路径有几条 
 27 int u,v,w;
 28 const int inf = 0x3f3f3f3f;
 29 stack<int>se;
 30 bool vis[N];
 31 void init()
 32 {
 33     for(int i =0;i<N;i++)
 34     {
 35         for(int j=0;j<N;j++)
 36         {
 37             f[i][j]=(i==j?0:inf);
 38         }
 39         dis[i] = inf;
 40         pre[i]=-1;
 41         vis[i] = 0;
 42         sval[i]=val[i];//易忘记 
 43     }
 44 }
 45 void dijk()
 46 {
 47     dis[s]=0;
 48     num[s]=1;//最重要的。 
 49     for(int i =0;i<n-1;i++)
 50     {
 51         int maxx,min_num;
 52         maxx=inf;
 53         for(int j=0;j<n;j++)
 54         {
 55             if(!vis[j]){
 56                 if(maxx>dis[j]){
 57                     maxx=dis[j];
 58                     min_num=j;
 59                 }
 60             }
 61         }
 62             vis[min_num]=1;
 63             for(int k=0;k<n;k++){
 64                 if(!vis[k]){
 65                 
 66                 if(dis[k]>dis[min_num]+f[min_num][k]){
 67                     dis[k]=dis[min_num]+f[min_num][k];    
 68                     sval[k]=sval[min_num]+val[k];
 69                     pre[k]=min_num;
 70                     num[k]=num[min_num];
 71                 }
 72                 else if(dis[k]==dis[min_num]+f[min_num][k]){
 73                     num[k]+=num[min_num];
 74                     if(sval[k]<sval[min_num]+val[k]){                    
 75                     sval[k]=max(sval[k],sval[min_num]+val[k]);
 76                     pre[k]=min_num;    //这里要改变前面的点因为最优路径只有一条 
 77                 }
 78                 }
 79             }
 80         }    
 81     }
 82 }
 83 int main()
 84 {
 85     scanf("%d%d%d%d",&n,&m,&s,&d);
 86     for(int i =0;i<n;i++) scanf("%d",&val[i]);
 87         init();//一定写在输入val[]之后 
 88     for(int i =0;i<m;i++)
 89     {
 90         scanf("%d%d%d",&u,&v,&w);
 91         f[u][v]=f[v][u]=w;
 92     }
 93     dijk();
 94     printf("%d %d\n",num[d],sval[d]);
 95     int i=d;
 96     se.push(i);
 97     while(pre[i]!=-1){
 98         i=pre[i];
 99         se.push(i);
100     }
101     while(!se.empty()){
102         int u =se.top();
103         if(u==d) break;
104         se.pop();
105         printf("%d ",u);
106     }
107     printf("%d\n",d);
108     return 0;
109 }