我们采用的是优先队列形式的Dijkstra算法,具体操作和解析如下代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>pi;
int maps[510][510]={0};//图的临界矩阵
int father[510];//保存最优上一级
int visit[510];//到访过了吗
int dis[510];//最优距离
int vle[510];//权值
int dpvle[510];//最优权值和
int sum[510];//种类数
int a,b,c,d;//输入值
int main()
{
cin>>a>>b>>c>>d;
for(int i=0;i<a;i++)cin>>vle[i];//我们输入权值
int x,y,z;
while(b--)//我们再输入边值
{
cin>>x>>y>>z;
maps[x][y]=maps[y][x]=z;//双向的哦
}
for(int i=0;i<a;i++)//始初化两个数组
{
father[i]=-1;
dis[i]=0x3f;
}
dis[c]=0;//起点距离为0
dpvle[c]=vle[c];//起点最优权值和为该点的权值
sum[c]=1;//最优路条数为1
visit[c]=1;//已访问
priority_queue<pi,vector<pi>,greater<pi>>que;//优先队列,pair排序是按第一个值排的
for(int i=0;i<a;i++)
{
if(visit[i]!=1&&maps[c][i]!=0)//相当于一个始初化
{
dis[i]=maps[c][i];//最优距离更新
que.push({dis[i],i});//所以我们将第一个值作为最优距离值
father[i]=c;//出发点更新
sum[i]=sum[c];//种类数继承
dpvle[i]=dpvle[c]+vle[i];//最优权值为上一个点的最优权值加上这个点的权值
}
}
while(!que.empty())//Dijkstra算法开始
{
int mdis=que.top().first;//距离
int mnode=que.top().second;//结点
que.pop();//出列
if(visit[mnode]==1)continue;//已访问过直接跳过
visit[mnode]=1;//以访问
for(int i=0;i<a;i++)//开始筛选
{
if(visit[i]==0&&maps[mnode][i]!=0)//满足更新条件的前提下才可以哦
{
if(dis[i]>dis[mnode]+maps[mnode][i])//如果当前最优距离不是最优了就替换掉
{
dis[i]=dis[mnode]+maps[mnode][i];
que.push({dis[i],i});//压入队列
father[i]=mnode;//父亲结点更新
sum[i]=sum[mnode];//最优路总数继承
dpvle[i]=dpvle[mnode]+vle[i];//最优权值变化
}
else if(dis[i]==dis[mnode]+maps[mnode][i])//如果出现一样的最优情况
{
sum[i]+=sum[mnode];//最短路总数增加
if(dpvle[i]<dpvle[mnode]+vle[i])//更新最优权值
{
dpvle[i]=dpvle[mnode]+vle[i];
father[i]=mnode;
}
}
}
}
}
//最后就是输出过程了
cout<<sum[d]<<" "<<dpvle[d]<<endl;
vector<int>lo;
int n1=d;
lo.push_back(d);
while(father[n1]!=-1)
{ n1=father[n1];
lo.push_back(n1);
}
int io=lo.size();
cout<<lo[io-1];
for(int i=io-2;i>=0;i--)cout<<' '<<lo[i];
}