题目详情 - 1030 Travel Plan (pintia.cn)
题目大意:给定n个城市,m条道路,每条道路有自己的距离和花费,给定起点终点,请你找到两点之间距离最短路径,如果有多条就找出其中花费最少的,并输出最短的路径以及其距离和花费。
思路分析:套用最短路算法--堆优化的dijkstra算法,不同点主要是有两个权重的更新,以及对路径的记录。当dist[j]>distance+w1[i]时,则更新最短距离和最少花费,并记录最短路径path。当dist[j]==distance+w1[i]时,如果cost[j]>costu+w2[i]则更新cost,并记录路径path。
#include<iostream>
#include<algorithm>
using namespace std;
#include<queue>
#include<cstring>
#include<vector>
typedef pair<int,int>pii;
typedef pair<pii,int>piii;
priority_queue<piii,vector<piii>,greater<piii>>heap;
const int N=510,M=2*N,INF=0x3f3f3f3f;
int h[N],e[M],ne[M],w1[M],w2[M],idx=0;//用于建图,w1,w2分别用于存储距离和花费
int n,m,S,D;
int dist[N],cost[N];
//dist,cost分别用于存储从起点出发所需距离的最小值,和在该距离下花费的最小值
bool st[N];//st数组表示该点是否已经确定最短路
int path[N]; //path数组用于存储到该点路径的前驱 ,如path[i]=j,表示到达i的前一个节点为j
void add(int a,int b,int d,int c){
e[idx]=b;
w1[idx]=d;
w2[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
void dijkstra(){
dist[S]=0;
cost[S]=0;//初始化
heap.push({{0,0},S});
while(heap.size()){//堆优化dijkstra算法模板
piii t=heap.top();
heap.pop();
pii tmp=t.first;
int u=t.second,distance=tmp.first,costu=tmp.second;
if(st[u]) continue;
st[u]=true;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
if(dist[j]>distance+w1[i]){
dist[j]=distance+w1[i];
cost[j]=costu+w2[i];
path[j]=u;//更新路径 u-j
heap.push({{dist[j],cost[j]},j});
}else if(dist[j]==distance+w1[i]){
if(cost[j]>costu+w2[i]){
cost[j]=costu+w2[i];
path[j]=u;//更新路径 u-j
heap.push({{dist[j],cost[j]},j});
}
}
}
}
}
}
int main(){
memset(h,-1,sizeof h);
memset(path,-1,sizeof path);
memset(dist,0x3f,sizeof dist);
memset(cost,0x3f,sizeof cost);
scanf("%d%d%d%d",&n,&m,&S,&D);
for(int i=0;i<m;i++){
int a,b,d,c;
scanf("%d%d%d%d",&a,&b,&d,&c);
add(a,b,d,c);
add(b,a,d,c);
}
dijkstra();
vector<int>v;
int i=D;
while(i!=S){
v.push_back(i);
i=path[i];
}
v.push_back(S);
for(int i=v.size()-1;i>=0;i--){//路径是反过来的所以要进行倒序输出
printf("%d ",v[i]);
}
printf("%d %d\n",dist[D],cost[D]);
return 0;
}