Logo handezheng 的博客

博客

最短路问题——Djikstra

...
handezheng
2025-12-01 12:50:48
崖谷涂足无人问,山巅独饮众生哗。

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2024-02-16 15:51:09

最短路问题—— Dijkstra

虽然并不是完全掌握


例题:

  1. P3371 【模板】单源最短路径(弱化版)
  2. P4779 【模板】单源最短路径(标准版)
  3. Dijkstra?
  4. P5905 【模板】全源最短路(Johnson)
  5. P1144 最短路计数

Dijkstra 的条件:

  1. 用于求最短路问题
  2. 确定起点

思想

运用贪心的思想,在当前起点的出边中找到 未被遍历 过的边权最小的点,将其标记并更新最短路径,直到遍历到终点。


实现:

  1. 邻接矩阵
    时间复杂度 $O(n^2)$。
\/\/map是邻接矩阵数组,map[i][i] = 0,若i,j之间没有边则map[i][j] = INF 
void Djikstra(int x){\/\/x是起点 
	memset(d,INF,siziof(d));\/\/求最短,初始化为较大数
	d[x] = 0;\/\/到他本身
	for(int i = 1;i <= n;i++){
		int j = 0;\/\/当前最小 
		for(int k = 1;k <= n;k++){\/\/找最小的未被访问的d[j] 
			if(!vis[k] && d[k] <= d[j]){
				j=k;
			}
		}
		vis[j] = 1;
		for(int k = 1;k <= n;k++){\/\/更新d[j] 
			d[k] = min(d[k],d[j] + map[j][k]);
		}
	} 
}
  1. 邻接表

时间复杂度 $O(n^2)$。

\/\/head是表头,ver是当前边的指向的点,nxt是下一条边,data是权值 
void Djikstra(int x){\/\/x是起点 
	memset(d,INF,siziof(d));\/\/求最短,初始化为较大数
	d[x] = 0;\/\/到他本身
	for(int i = 1;i <= n;i++){
		int j = 0;\/\/当前最小 
		for(int k = 1;k <= n;k++){\/\/找最小的未被访问的d[j] 
			if(!vis[k] && d[k] <= d[j]){
				j=k;
			}
		}
		vis[j] = 1;
		for(int k = head[j];k != -1;k = nxt[k]){\/\/更新d[j] 
			d[ver[k]] = min(d[ver[k],d[j]]+data[k]);
		}
	} 
}

堆(优先队列)优化

优化条件

  1. 边权非负
  2. 边数远小于$n^2$,即$cnt(edge) \le 2\cdot10^5$

vector做法

时间复杂度 $O(m\cdot log_2m)$

struct node{
	int d;\/\/d是当前的最短路径 
	int u;\/\/u是起点 
	bool operator < (const node & rhs) const {
		return d > rhs.d;
	}\/\/重载运算符
};

vector <int> e[N];\/\/e[i][]表示第i个点所连的所有边
vector <int> w[N];\/\/w[i][]表示e[i][]所连边的权值

void Dijkstra(){
	
	priority_queue <node> q;
	F(2,i,n) d[i]=INF;
	node tn;
	tn.d=0,tn.u=1;
	q.push(tn);
	int u;
		\/\/初始化 
	
	while(!q.empty()){
		node t=q.top();
		q.pop();
		u=t.u;
		if(vis[u]) continue;\/\/要求未被标记
		vis[u]=1;
		for(int i = 0;i < e[u].size();i++){\/\/vector默认从0开始,遍历从u到达的边		 
			int v = e[u][i];\/\/v是终点
			if(d[v] > d[u] + w[u][i]){\/\/这条路径的长度小于当前最短路径 
				d[v] = d[u] + w[u][i];\/\/更新最短路径
				pre[v]=u;\/\/记忆路径
				tn.d=d[v],tn.u=v;
				q.push(tn);\/\/作为新起点入堆
			}
		} 
	}
	 
}

萌新第一次写博客

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。