Dijkstra堆优化解析

用vector数组来存储每个节点的相邻节点

#include<iostream>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1000010;
/*
	边尾=====>边头
*/
struct qnode {
	int v;//顶点index
	int c;//源点到该顶点的最短距离
	qnode(int _v = 0, int _c = 0) :v(_v), c(_c) {}
	//重载<, 变成最小堆(根据源点到节点的路径长度从大到小排,优先队列中top元素是最小的)
	bool operator <(const qnode& r)const {
		return c > r.c;
	}
};
struct Edge {
	int v, cost;//和找到的最短路径节点相邻的顶点,连接这两个顶点边权重
	Edge(int _v = 0, int _cost = 0) :v(_v), cost(_cost) {}
};
vector<Edge>AdjList[MAXN];//类似邻接表(边节点以顺序表存储)
bool vis[MAXN];//访问数组
int dist[MAXN];//距离数组
//点的编号从 1 开始
void Dijkstra(int n, int start) {	//顶点数,源点
	memset(vis, false, sizeof(vis));//访问数组初始化全false
	for (int i = 1; i <= n; i++)	//距离数组初始化inf
		dist[i] = INF;
	priority_queue<qnode>que;
	dist[start] = 0;
	que.push(qnode(start, 0));//源点入队
	qnode tmp;
	while (!que.empty()) {
		tmp = que.top();	//因为重载了<,top节点到源点距离一定是最短的
		que.pop();
		int u = tmp.v;		//找到的最短路径节点的节点号u
		if (vis[u])			//判断是否已经访问过了
			continue;
		vis[u] = true;		//设置成已访问
		//对当前找到的最短路径节点的边界点组访问(和该节点相邻的节点,用到邻接表知识)
		for (int i = 0; i < AdjList[u].size(); i++) {
			int v = AdjList[u][i].v;	//边头节点
			int cost = AdjList[u][i].cost;//边权重
			//1.这个节点没被访问
			//2.上一轮源节点到该节点的距离>从源点到当前最短路径节点距离+当前最短路径节点到这个节点的距离
			if (!vis[v] && dist[v] > dist[u] + cost) {
				dist[v] = dist[u] + cost;//更新
				que.push(qnode(v, dist[v]));//进入优先队列,为下一轮找最短路径节点做准备
			}
		}
	}
}
//边尾,边头,权重
//向类似邻接表添加边
void addedge(int u, int v, int w) {
	AdjList[u].push_back(Edge(v, w));
}

int main() {
	addedge(1, 3, 8);
	addedge(3, 4, 5);
	addedge(4, 5, 6);
	addedge(1, 2, 13);
	addedge(2, 6, 9);
	addedge(2, 7, 7);
	addedge(1, 5, 30);
	addedge(5, 6, 2);
	addedge(6, 7, 17);
	addedge(1, 7, 32);
	Dijkstra(7, 1);
	cout << "以V1为起点,到各点的最短路径:" << endl;
	for (int i = 1; i <= 7; i++)
		cout << 'V' << i  << "\t";
	cout << endl;
	for (int i = 1; i <= 7; i++)
		printf("%2d\t", dist[i]);

}

测试例子:
在这里插入图片描述
测试结果:
在这里插入图片描述

例题

在这里插入图片描述

class Solution {
public:
	double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start, int end) {
		vector<bool> vi(n, false);//访问数组

		vector<vector<pair<double, int>>> path(n, vector<pair<double, int>>());
		for (int i = 0; i < edges.size(); i++) {//邻接表
			auto& e = edges[i];
			path[e[0]].push_back({ succProb[i], e[1] });
			path[e[1]].push_back({ succProb[i], e[0] });
		}

		priority_queue<pair<double, int>> pq;//默认最大堆,根据pair中首个元素double排序
		pq.push({ 1.0, start });		//首元素,概率设置为1

		while (!pq.empty()) {
			auto [curProb, cur] = pq.top();//这种写法仅支持c++17之后
			pq.pop();

			if (vi[cur]) continue;
			vi[cur] = true;

			if (cur == end) return curProb;

			for (auto[nextProb, next] : path[cur]) {//对相邻节点 bfs
				if (vi[next]) continue;
				pq.push({ curProb * nextProb, next });
			}
		}

		return 0;
	}

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值