L2-001 紧急救援 (25 分)
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
/*
解题思路:
感觉就是在求最短路径的基础上再加一个最大救援人数
和最短路径数。
对于Dijkstra算法思路:
1、初始化
2、循环n次
{
在所有未标记节点中,选出D值(权值)小的节点x
给x标记
对于从x出发的所有边(x,y),更新D[y]=min{D[y],D[x]+T[x][y]} ,以及
救援队人数值和路径条数
}
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,o,p;// 城市、路径、初始点、终点
int team[510],flag[510]={false},sum_team[510];//城市救援队人数、用于标记、从初始点到该城市的救援队人数总数
int T[510][510]; //存储两个城市间的权值
int D[510],P[510];//最短路径、父节点
int Road[510];//最短路径数
void Dj(int a)
{
//初始化
for(int i=0;i<n;i++)
{
D[i]=T[a][i];
if(D[i]!=maxn)
{
P[i]=a;
sum_team[i]=team[a]+team[i];
Road[i]=1;
}
}
flag[a]=true;
Road[a]=1;
D[a]=0;
sum_team[a]=team[a];
//找最小节点
for(int i=1;i<n;i++)
{
int minid=-1,min_d=maxn;
for(int j=0;j<n;j++)
{
if(!flag[j]&&D[j]<min_d)
{
minid=j;
min_d=D[j];
}
}
if(minid==-1) return ;
flag[minid]=true;//标记
//更新数值
for(int j=0;j<n;j++)
{
if(!flag[j]&&T[minid][j]!=maxn)
{
if(D[j]>D[minid]+T[minid][j])
{
D[j]=D[minid]+T[minid][j];
P[j]=minid;
sum_team[j]=sum_team[minid]+team[j];
Road[j]=Road[minid];
}
else if(D[j]==D[minid]+T[minid][j])
{
if(sum_team[j]<sum_team[minid]+team[j])
{
P[j]=minid;
sum_team[j]=sum_team[minid]+team[j];
}
Road[j]+=Road[minid];
}
}
}
}
}
int main(void)
{
cin>>n>>m>>o>>p;
for(int i=0;i<n;i++ )//救援队人数录入
{
int a;
cin>>a;
team[i]=a;
}
for(int i=0;i<n;i++)//无向图初始化最大
{
for(int j=0;j<n;j++)
{
T[i][j]=maxn;
}
}
for(int i=0;i<m;i++)//城市路径录入
{
int a,b,w;
cin>>a>>b>>w;
T[a][b]=w;
T[b][a]=w;
}
Dj(o);
cout<<Road[p]<<" "<<sum_team[p]<<endl;
//从终点利用P数组回溯到初始点,将路径上的值保存在栈中
stack<int> s;
s.push(p);
p=P[p];
while(p!=o)
{
s.push(p);
p=P[p];
}
cout<<o;
while(!s.empty())
{
int q=s.top();
s.pop();
cout<<" "<<q;
}
cout<<endl;
return 0;
}