三种最短路径的模板
1.迪杰斯特拉(dijkstra):
(1)朴素版:
1 void dijkstra() 2 { 3 int g,minx; 4 z[s]=1;//起点标记 5 for(int i=1;i<=n;i++)//初始化 6 { 7 dist[i]=v[s][i]; 8 } 9 for(int i=1;i<=n;i++)//n个节点,找n次 10 { 11 minx=INT_MAX; 12 for(int j=1;j<=n;j++) 13 { 14 if(!z[j]&&(dist[j]<minx))//寻找未被标记的最小节点 15 { 16 minx=dist[j]; 17 g=j; 18 } 19 } 20 z[g]=1;//标记被找到的最小节点 21 for(int k=1;k<=n;k++) 22 { 23 if(!z[k]&&dist[k]>(dist[g]+v[g][k]))//更新节点(s->k大于s->g->k) 24 { 25 dist[k]=dist[g]+v[g][k]; 26 } 27 } 28 } 29 }
(2)邻接表存图+优先队列优化
1 void dijkstra() 2 { 3 //初始化 4 fill(dis,dis+maxn,inf); 5 dis[s]=0; 6 q.push(make_pair(0,s));//第一维存储dis的相反数:把大根堆转化为小根堆 7 //直到队列为空,没有更短路径 8 while(!q.empty) 9 { 10 //获取队头元素,有push就有pop 11 int x=q.top().second; 12 q.pop(); 13 //是否以及添加进图中 14 if(vis[x]==1) 15 continue; 16 vis[x]=1;//添加 17 //松弛操作,基于终点 18 for(int i=head[x];i!=0;i=edge[i].next) 19 { 20 int to=edge[i].to; 21 if(!vis[to]&&dis[to]>dis[x]+edge[i].dis) 22 { 23 dis[to]=dis[x]+edge[i].dis; 24 //入队 25 q.push(make_pair(-dis[to],to)); 26 } 27 } 28 } 29 }
2.贝尔曼福特(bellman_ford):
(1)朴素+优化:
1 void bellman_ford() 2 { 3 //初始化 4 fill(dis,dis+maxn,inf); 5 dis[s]=0; 6 //核心:两层循环 7 for(int i=1;i<=n-1;i++) 8 { 9 check=0; 10 for(int j=1;j<=m;j++) 11 { 12 //松弛操作,基于起点 13 if(dis[u[i]]!=inf&&dis[v[i]]>dis[u[i]]+w[i]) 14 { 15 dis[v[i]]=dis[u[i]]+w[i]; 16 check=1; 17 } 18 } 19 //如果没有进行新的松弛操作,说明已经是最短路径,结束循环便可 20 if(check==0) 21 break; 22 } 23 //判断是否有负权回路 24 for(int i=1;i<=n-1;i++) 25 { 26 for(int j=1;j<=m;j++) 27 { 28 if(dis[v[i]]>dis[u[i]]+w[i]) 29 { 30 flag=1; 31 break; 32 } 33 } 34 } 35 //输出 36 if(flag==0) 37 { 38 //输出最短路径 39 } 40 else 41 //有负权回路 42 }
(2)队列优化,邻接表存图:
1 //first[],next[],u[],v[],w[]:邻接表 2 //book标记是否在队列中 3 void bellman_ford() 4 { 5 //初始化 6 fill(dis,dis+maxn,inf); 7 dis[s]=0; 8 book[s]=1; 9 q.push(s); 10 //循环,队列不为空 11 while(!q.empty()) 12 { 13 //取队头 14 int k=first[q.front()]; 15 //取的顶点在已有范围内 16 while(k!=-1) 17 { 18 //松弛操作 19 if(dis[v[k]]>dis[u[k]]+w[k]) 20 { 21 dis[v[k]]=dis[u[k]]+w[k]; 22 //顶点v[k]不在队列中,则加入到队列并标记 23 if(book[v[k]]==0) 24 { 25 q.push(k[v]); 26 book[v[k]]=1; 27 } 28 } 29 //取下一个k,链表结构 30 k=next[k]; 31 } 32 //出队 33 q.pop(); 34 } 35 }
3.弗洛伊德算法(floyed):
1 //基于已有的矩阵 2 void floyed() 3 { 4 //初始化 5 cin>>n>>m; 6 for(int i=1;i<=n;i++) 7 { 8 for(int j=1;j<=n;j++) 9 { 10 //初始化矩阵对角线为0 11 if(i==j) 12 dis[i][j]=0; 13 else 14 dis[i][j]=inf; 15 } 16 } 17 for(int i=1;i<=m;i++) 18 { 19 cin>>u>>v>>w; 20 dis[u][v]=w; 21 } 22 //核心,三个循环,5行 23 for(int k=1;k<=n;k++) 24 { 25 for(int i=1;i<=n;i++) 26 { 27 for(int j=1;j<=n;j++) 28 { 29 if(dis[i][j]>dis[i][k]+dis[k][j]) 30 { 31 dis[i][j]=dis[i][k]+dis[k][j]; 32 } 33 } 34 } 35 } 36 }
三种算法的时间,空间复杂度以及适用情况

——《啊哈!算法》

浙公网安备 33010602011771号