Dijkstra算法模板及其优先队列优化~~

Dijkstra算法:用于解决 非负路权 单源 最短路问题


无优化的Dijkstra算法

int N, G[maxn][maxn] = { 0 };  //N为结点数目(编号0 ~ N-1)
int d[maxn], pre[maxn];        //G为邻接矩阵,G[u][v]=0表示 u、v无通路
bool vis[maxn] = { false };

void Dijkstra(int s)           //s为起点
{
	fill(d, d + maxn, INF);
	fill(pre, pre + maxn, -1);      //-1表示无前驱结点
	d[s] = 0;                       //起点s到自身距离为0,其他全为INF
	for (int i = 0; i < N; i++)
	{
		int u, Min = INF;           //找到 未访问的结点 中 d最小的———— u
		for (int j = 0; j < N; j++)
		{
			if (!vis[j] && d[j] < Min)
			{
				u = j;
				Min = d[j];
			}
		}
		vis[u] = true;                 //对 u进行访问
		for (int v = 0; v < N; v++)    //以 u为踏板优化 u能直接到达 的结点v
		{
			if (!vis[v] && G[u][v] && d[u] + G[u][v] < d[v])
			{
				d[v] = d[u] + G[u][v];
				pre[v] = u;
			}
		}
	}
}


对Dijkstra算法进行优化就在于 找到未访问的结点 中 d最小的

  1. 利用优先队列:O(logN)的时间复杂度,令d最小的置于队首。

  2. 可以发现只有上一轮更新过的结点,d才会变小,所以并不需要将所有结点放入优先队列,只要放入被更新(且未被访问过)的结点即可。(对于Dijkstra算法访问过的结点u,则d[u] 就已是最小值)

注意:由于优先队列中只是存储一个状态的 d[num],队列中并不会更新,所以队列中可能会出现不同d的同一个结点,因此要加上:

if(vis[u]) 
	continue;
else
	vis[u] = true;  

队列优化的Dijkstra算法

struct Node
{
	int num;     //编号
	int d;       //起点s到达num的最短路程
	friend bool operator < (const Node &a, const Node &b)
	{
		return a.d > b.d;       //重载<运算符,令d小的优先度高
	}
};
int N, G[maxn][maxn] = { 0 };
int d[maxn], pre[maxn];
bool vis[maxn] = { false };

void Dijkstra(int s)
{
	fill(d, d + maxn, INF);
	fill(pre, pre + maxn, -1);
	d[s] = 0;
	priority_queue<Node> q;
	Node t = { s,d[s] };
	q.push(t);
	while (!q.empty())
	{
		int u = q.top().num;     //取当前队首结点u
		q.pop();
		if(vis[u])               //若u已被访问过,说明当前 d并不是最小值,直接跳过
			continue;
		else
			vis[u] = true;              //否则对 u进行访问
		for (int v = 0; v < N; v++)     //以 u为踏板优化 u能直接到达 的结点v
		{
			if (!vis[v] && G[u][v] && d[u] + G[u][v] < d[v])
			{
				d[v] = d[u] + G[u][v];
				pre[v] = u;
				t.num=v;
				t.d=d[v];
				q.push(t);
			}
		}
	}
}

你可能感兴趣的:(★Tips,★图论,#,【最短路】)