#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int sum[550];//储存每个点的人数
int tu[550][550],dij[550];
bool st[550];//标记数组迪杰斯特拉算法必备
int lu[550];//储存每个点的前一个节点
int num[550],lu_num[550];//储存到达每个点以后可以召集的救援人数;
const int INF=0x3f3f3f;
void dijst(int n,int s,int d){
lu_num[s]=1,num[s]=sum[s];
for(int i=0;i<550;i++){
dij[i]=INF;
}
dij[s]=0;
for(int i=1;i<=n;i++){
int t=-1;
for(int j=0;j<n;j++){
if(st[j]==0&&(t==-1||dij[j]<dij[t])){
t=j;
}
}
if(t==-1)return;
st[t]=1;//以上都是很基础的迪杰斯特拉算法
for(int j=0;j<n;j++){
if(j==t)continue;//因为下面会对点进行更新操作所以要跳过本身的点;
if(dij[j]==(dij[t]+tu[t][j])){
if(num[j]<sum[j]+num[t]){
num[j]=sum[j]+num[t];
lu[j]=t;//j的上一个点是t
}
lu_num[j]=lu_num[j]+lu_num[t];//到达j这个点的总条数为没加入t点之前的总数,和到达t点的路径和
}else
if(dij[j]>dij[t]+tu[t][j]){//此时说明有更短的道路
dij[j]=dij[t]+tu[t][j];
num[j]=sum[j]+num[t];
lu[j]=t;
lu_num[j]=lu_num[t];
}
}
}
}
void print(int s,int d,int k){//输出路径
if(k==s){
cout<<k<<" ";
return;
}
print(s,d,lu[k]);//递归方式
cout<<k;
if(k!=d)cout<<" ";
}
int main(){
int n,m,s,d;
cin>>n>>m>>s>>d;
for(int i=0;i<n;i++){
cin>>sum[i];
}
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
tu[i][j]=INF;
if(i==j)tu[i][j]=0;
}
}
for(int i=1;i<=m;i++){
int a,b,l;
cin>>a>>b>>l;
tu[a][b]=l;
tu[b][a]=l;
}
dijst(n,s,d);
cout<<lu_num[d]<<" "<<num[d]<<endl;
int k=d;
print(s,d,k);
cout<<endl;
return 0;
}
挺简单的一道图论题,最短路算法小变形。包含最短路算法和记录最短路路径。可用作相似题的模板。