1030 Travel Plan PAT 甲级 记录最短路径的最短路Dijkstra

题目详情 - 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;
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值