[蓝桥杯 2022 国 B] 出差(Dijkstra + 优先队列)

        首先根据题目描述,我们可以得知我们需要寻找到起点到终点的最短时长(最短路径问题),而要找出最短路径问题,我们可以用迪杰克拉算法,就是从起始点开始遍历,用优先队列优先从最短路径的点开始遍历,如果花费时间存在更小方案就更新dist数组,最后直接输出dist[n] - time[n]即可

上代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#include<vector>
#include<queue>

using namespace std;

typedef pair<int,int> PII;

struct Node{
	int value;
	vector <Node*> children;//存储子节点 
	int time;//存储时间 
	vector <int> length;//存储路径权值 
};

int n, m;

unordered_map <int, Node*> mp;
const int N = 1e3 + 10;
int dist[N]; 
bool st[N] = {0};//存储每个点的访问情况,如果已经有最短路径了,就标志为1 

void djkl()
{
	//参数分别是当前节点到目标点的最短距离,以及目标点,第二个参数是用vector作为底层容器,第三个是按照从小到大依次排列,如果要从大到小就用less<PII> 
	priority_queue<PII, vector<PII>, greater<PII>> q;
	memset(dist, 0x3f3f3f3f, sizeof(dist));//初始化dist数组为最大值
	dist[1] = 0;//起始点到起始点的距离是0 
	q.push({0, 1});//初始化优先队列,先将起点放进来,第一个参数0表示路径长度为0,1表示目标点
	
	while(!q.empty()){
		auto t = q.top(); q.pop();//取出当前信息
		
		if(st[t.second]) continue;//如果当前点是最优的点,就继续向下访问
		st[t.second] = true;//否则就标记当前点
		
		for(int i = 0; i < mp[t.second]->children.size(); i++){//从当前点开始访问其他可通路径
			int num = mp[t.second]->children[i]->value;//取出下一个点的编号
			
			//如果到当前点所花费的时间大于到上一个点花费的最短时间和隔离时间还有路径时间的总和,就进行更新 
			if(dist[num] > dist[t.second] + mp[t.second]->length[i] + mp[num]->time){
				dist[num] = dist[t.second] + mp[t.second]->length[i] + mp[num]->time;
				q.push({dist[num], num});//更新队列 
			} //因为起始点不用隔离,因此直接用子节点的隔离时间 
		}
	} 
	cout << dist[n] - mp[n]->time << endl;//因为到达第n个城市不需要隔离,因此需要减去当前隔离时间 
	return;
}
 
int main(void)
{
	cin >> n >> m;
	Node node[n + 10];
	
	for(int i = 1; i <= n; i++){
		node[i].value = i;
		mp[i] = &node[i];
		int time1; cin >> time1;
		mp[i]->time = time1;
	}
	for(int i = 1; i <= m; i++){
		int x, y, z;
		cin >> x >> y >> z;
		mp[x]->children.push_back(mp[y]);
		mp[y]->children.push_back(mp[x]);
		mp[x]->length.push_back(z);
		mp[y]->length.push_back(z); 
	}	
	djkl();
	
	return 0;
}

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值