最短路总结2 堆优化dijkstra

最短路系列链接
最短路总结1 最短路问题概述与朴素dijkstra
最短路总结2 堆优化dijkstra
最短路总结3 BellmanFord
最短路总结4 SPFA及应用
最短路总结5 floyd

文章目录

            • 1.朴素dijkstra的改进
            • 2.priority_queue
            • 3.模板
            • 4.板子题

1.朴素dijkstra的改进

朴素dijkstra的流程:

  1. 初始化各点到源点的距离
  2. 迭代n-1次(除源点外有n-1个点)
    (1)在最短路未确定的点中,找距离源点最近的点v。(用bool数组标识该点的最短路是否已经确定)
    (2)用v点去更新全图所有点的当前最短路距离(dist[])
    (3)若i点满足:dist[i] > dist[v] + w[v][i]则更新i点的dist值
    更新全图后将该点设置为最短路已经确定

在整个流程中,时间复杂度的上限由2.(1)也就是”在最短路未确定的点中,找距离源点最近的点v。“这一步决定,因为这一步时间复杂度最大。堆优化版就是利用堆的快速自维护顺序的特性,加快这一过程。

2.priority_queue
  1. C++里的堆,其实就是优先队列,头文件
  2. 默认声明的优先队列是大根堆,需要小根堆时(比如我们这里找距离源点最近的点)需要声明为:priotity_queue,greater> q;
  3. 当需要使用其他类型的变量作为元素时,将上述int改变即可,如:
typedef pair<int,int> pa;
priotity_queue<pa,vector<pa>,greater<pa>> q;
3.模板
  1. 算法原理没有改变,但是堆优化版一般用于稀疏图,用邻接表存储。
  2. 由于用优先队列存储,存在一个问题:优先队列并不能像数组那样任意的修改元素,在优先队列中,假如要更新元素,实际操作是:将新的元素直接插入优先队列,旧的元素不管。由于优先队列会自动维护顺序,更新后的元素的距离肯定比旧元素的距离小,则旧元素必定向堆的底部下沉,新元素必定在旧元素的上方,当取出元素时,新元素也就是距离小的元素一定会最先被取出,此时设置一个bool标识已取出,后面遇到的直接跳过即可。
typedef pair<int, int> PII;

int n;      // 点的数量
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储所有点到1号点的距离
bool st[N];     // 存储每个点的最短距离是否已确定

// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});      // first存储距离,second存储节点编号
    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();

	int ver = t.second, distance = t.first;
	if (st[ver]) continue;
        st[ver] = true;

	for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > distance + w[i])
            {
                dist[j] = distance + w[i];
                heap.push({dist[j], j});
            }
        }
   }
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
4.板子题

给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
输入格式
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
输出格式
输出一个整数,表示1号点到n号点的最短距离。
如果路径不存在,则输出-1。
数据范围
1≤n,m≤1.5×1051≤n,m≤1.5×105,
图中涉及边长均不小于0,且不超过10000。
输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3

#include
#include
#include
#include
#include

using namespace std;

typedef pair<int,int> pa;
const int N=150050,inf=0x3f3f3f3f;
int n,m;
vector<int> g[N];
vector<int> ww[N];
int dist[N];
bool st[N];
priority_queue<pa,vector<pa>,greater<pa> > q;

int dijkstra() {	
	memset(dist,inf,sizeof(dist));	
	dist[1]=0;
	q.push({0,1});
	while(q.size()) {
		pa t=q.top();
		q.pop();
		int dis=t.first,v=t.second;
		if(st[v]) continue;
		st[v]=1;
 
  		for(int i=0;i<g[v].size();i++) {
   			int k=g[v][i];
   			int w=ww[v][i];
			if(dist[k]>dis+w) {
			dist[k]=dis+w;
			q.push({dist[k],k});
   			}
  		}
	}

	if(dist[n]>=inf) return-1;
	else return dist[n];
}
int main()
{
 cin >> n >> m;
 while(m --) {
 	int x,y,z;
  	cin >> x >> y >> z;
	if(x!=y) {
	   g[x].push_back(y);
	   ww[x].push_back(z);
	  }
 } 
 int t=dijkstra();
 cout << t;
 
 return 0;
}


你可能感兴趣的:(数据结构+算法)