本题是一道最短路径水题,和普通最短路径不一样的是,本题不仅要考虑路径长度,还要考虑路径上的花费。除此之外,还要输出路径。考虑路径上的花费比较简单,直接在SPFA的时候添加判断即可,输出路径则在存边的时候开两个数组,一个专门存前驱,一个专门存后继。在最后,倒序遍历,就可以找到唯一的一条最短路径。
#include <iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<cstdlib>
#include<queue>
#include<cstring>
#include<set>
using namespace std;
int n,m,s,t;
int c[520];
int in[520]={0};//节点是否在队列中
int dis[520];
int cost[520];
queue<int>q;
set<int>pre[520];//每个节点的前驱节点
struct Node
{
int v;
int w;
int u;
int cost;
Node(int _u,int _v,int _w,int _cost):u(_u),v(_v),w(_w),cost(_cost){
}
};
vector<Node>a[520];
vector<Node>b[520];
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
fill(dis+0,dis+n+10,0x3f3f3f3f);
fill(cost,cost+n+10,0x3f3f3f3f);
for(int i=1;i<=m;i++)
{
int x,y,z,zz;
scanf("%d%d%d%d",&x,&y,&z,&zz);
a[x].push_back(Node(x,y,z,zz));
a[y].push_back(Node(y,x,z,zz));
b[x].push_back(Node(y,x,z,zz));
b[y].push_back(Node(x,y,z,zz));
}
in[s]=1;
dis[s]=0;
cost[s]=0;
q.push(s);
while(!q.empty())
{
int head=q.front();
q.pop();
in[head]=0;
for(int i=0;i<a[head].size();i++)
{
int dis1=a[head][i].w;
int cost1=a[head][i].cost;
int v=a[head][i].v;
if(dis[v]>dis[head]+dis1)
{
dis[v]=dis[head]+dis1;
cost[v]=cost[head]+cost1;
if(!in[v])
{
in[v]=1;
q.push(v);
}
}
else if(dis[v]==dis[head]+dis1)
{
if(cost[v]>cost[head]+cost1)
{
cost[v]=cost[head]+cost1;
if(!in[v])
{
in[v]=1;
q.push(v);
}
}
}
}
}
vector<int>ans;
int cur=t;
while(true)
{
ans.push_back(cur);
if(cur==s)
break;
for(int i=0;i<b[cur].size();i++)
{
int u=b[cur][i].u;
int w=b[cur][i].w;
int ww=b[cur][i].cost;
if(dis[cur]==dis[u]+w&&cost[cur]==cost[u]+ww)
{
cur=u;
break;
}
}
}
for(int i=ans.size()-1;i>=0;i--)
cout<<ans[i]<<" ";
cout<<dis[t]<<" "<<cost[t];
}