Dijkstra
Dijkstra
-
本质:BFS+贪心,对点进行操作
-
特点:单源最短路,求解一个源点到其他所有点的最短距离
-
存储结构:链式前向星
-
适用对象:非负权图(一旦顶点已经确定最短路,其将不再被考查, d i s dis dis将不再改变);不能求最长路
-
核心思想:不断贪心选取 { d i s } \set{dis} {dis}中最小的顶点 U U U,并更新其邻接点 V V V的最短路
-
算法流程:设源点 s s s,已确定最终最短路点集 { S } \set{S} {S}(初始 { S } = ∅ ) \set{S}=\varnothing) {S}=∅);各点当前最短路长度 { d i s } \set{dis} {dis}(初始 { d i s } = + ∞ \set{dis}=+\infty {dis}=+∞(非 s s s,表示该点目前不可达), 0 ( s ) 0(s) 0(s)),目前最短路方案数组 p a t h path path(存储其上一个来源顶点,初始化为 − 1 -1 −1表示无路径),待算法结束后即为最终最短路方案;当前轮起点 U U U, U U U邻接点集 { V } \set{V} {V},邻接点权值集 { W } \set{W} {W}。三角形不等式: d i s ( s , v ) ( 最终 ) ≤ d i s ( s , u ) + d i s ( u , v ) dis(s,v)(最终)\le dis(s,u)+dis(u,v) dis(s,v)(最终)≤dis(s,u)+dis(u,v)
循环执行下列步骤,直到点集 { S } \set{S} {S}中包含所有顶点或剩余未进入 { S } \set{S} {S}的顶点 d i s dis dis值均无法更新:-
考查最小顶点(贪心):从点集 { S } \set{S} {S}中找 d i s dis dis最小且先前未被考查的顶点 U U U作为当前轮起点(首次即为源点 s s s),考查顶点 U U U
-
松弛入度边( B F S BFS BFS扩散):扩散到 U U U邻接点且先前未被考查的顶点 V V V,检查是否能通过 U U U作为中转而使 V V V的 d i s dis dis更短(松弛, d i s [ V ] = m i n ( d i s [ V ] , d i s [ U ] + W ) dis[V]=min(dis[V],dis[U]+W) dis[V]=min(dis[V],dis[U]+W),若被松弛, p a t h [ V ] = U path[V]=U path[V]=U)
-
-
复杂度:朴素版 O ( V 2 ) O(V^2) O(V2),二叉堆优化版 O ( V log 2 V + E ) O(V\log_2V+E) O(Vlog2V+E)
using ll=long long;
using pll=pair<ll,ll>;
const ll INF=__LONG_LONG_MAX__;
extern ll n,m,s;//点数,边数,源点
struct vertex{
int e=-1;
}v[n];
struct edge{
int u,v,w,n=-1;
}e[m];
朴素版
- 选目前 d i s dis dis最小点 U U U的3个条件:该点未被考查,该点 d i s dis dis非无穷,该点 d i s dis dis更小
- 扩散至 U U U邻接点 V V V的3个条件:该邻接点未被考查,边权值非无穷, V V V通过 U U U中转 d i s dis dis更短
void dijkstra(){
vector<bool>S(n,0);
vector<ll>dis(n,INF),path(n,-1);
dis[s]=0;
for(ll k=0;k<n;k++){//尽可能使未选点集添加到已选点集
ll U=-1,minn=INF;
for(ll i=0;i<n;i++)//贪心选dis最小点
if(!S[i]&&dis[i]!=INF&&dis[i]<minn)//3个条件:该点未被考查,该点dis非无穷,该点dis更小
U=i,minn=dis[i];
if(U==-1) break;//特判:剩余点均不可达
S[U]=1;//考查最小点
for(ll i=v[U].e;~i;i=e[i].n){//BFS扩散邻接点 ~i:i!=-1
ll V=e[i].v,W=e[i].w;
if(!S[U]&&W!=INF&&dis[V]>dis[U]+W)//松弛3个条件:该邻接点未被考查,边权值非无穷,邻接点通过当前起点中转dis更短
dis[V]=dis[U]+W,path[V]=U;
}
}
}
二叉堆优化版
-
选目前 d i s dis dis最小点 U U U的3个条件:该点未被考查,该点 d i s dis dis非无穷,该点 d i s dis dis更小。选取 d i s dis dis最小点是通过另设 d i s dis dis的小根堆 Q Q Q动态维护目前 d i s dis dis最小点 U U U实现的。
-
扩散至 U U U邻接点 V V V的3个条件:该邻接点未被考查,边权值非无穷, V V V通过 U U U中转 d i s dis dis更短
void dijkstra(){
vector<bool>S(n,0);
vector<ll>dis(n,INF),path(n,-1);
priority_queue<pii,vector<pii>,greater<>>pq;//小根堆,first存顶点dis,second存顶点编号
dis[s]=0,pq.push({dis[s],s});
while(pq.size()){
ll U=pq.top().second;
pq.pop();
if(S[U]) continue;//若已被考查过,直接跳过
S[U]=1;//考查堆顶最小点
for(ll i=v[U].e;~i;i=e[i].n){//BFS扩散邻接点 ~i:i!=-1
ll V=e[i].v,W=e[i].w;
if(!S[V]&&W!=INF&&dis[V]>dis[U]+W)//松弛邻接点入度边
//松弛3个条件:该邻接点未被考查,边权值非无穷,邻接点通过当前起点中转dis更短
dis[V]=dis[U]+W,path[V]=U,pq.push({dis[V],V});
}
}
}
路径输出
void print(ll s,ll t){
if(!(~path[t])){cout<<-1<<' ';return;}
if(s==t){cout<<s<<' ';return;}
print(s,path[t]);
cout<<t<<' ';
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具