(1)dijkstra
N个节点,循环N次,每次循环取出当前未确定最短路径的最小值ind,确定其为最短路径,并把ind可到达的节点更新。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct Node {
int v, dist;
};
const int MAXN = 100010,inf=0x7fffffff;
vector <Node> G[MAXN];
int m, N;
int vis[MAXN],d[MAXN];
int pre[MAXN];
void dijkstra(){
memset(vis, 0,sizeof(vis));
d[1]=0;
for(int i=2;i<=N;i++) d[i]=inf;
int ind=0;
for(int i=0;i<N;i++){
int _min=inf;
for(int j=1;j<=N;j++)
if(vis[j]==0&&_min>d[j]){
_min=d[j];
ind=j;
}
if(_min==inf)
break;
vis[ind]=1;
for(int k=0;k<G[ind].size();k++){
int v=(int)G[ind][k].v;
if(v!=-1&&d[ind]+(int)G[ind][k].dist<d[v]){
d[v]=d[ind]+(int)G[ind][k].dist;
pre[v]=ind;
}
}
}
}
int main(){
freopen("data","r",stdin);
freopen("data.out1","w",stdout);
while(cin>>N>>m){
for(int i=0;i<MAXN;i++){
G[i].clear();
}
memset(vis,0,sizeof(vis));
for (int i=1;i<=m;i++)
{
int from,to,dist;
scanf("%d%d%d",&from,&to,&dist);
G[from].push_back((Node){to,dist});
G[to].push_back((Node){from,dist});
}
dijkstra();
cout<<d[N]<<endl;
}
}
输入:
5 7
1 2 8
1 4 10
2 3 9
2 4 10
2 5 1
3 4 7
3 5 10
输出:
9
(2)优先队列优化的dijkstra
先上代码:
void dijkstra_queue(){
priority_queue< Node>pq;
pq.push((Node){1,0});
memset(vis,0,sizeof(vis));
vis[1]=1;
d[1]=0;
for(int i=2;i<=N;i++) d[i]=inf;
while(!pq.empty()){
int ind=(int)pq.top().v;
pq.pop();
vis[ind]=1;
cout<<"出队元素"<<ind<<endl;
cout<<"入队元素";
for(int k=0;k<G[ind].size();k++){
int v=(int)G[ind][k].v;
if(v!=-1&&d[v]>d[ind]+(int)G[ind][k].dist){
d[v]=d[ind]+(int)G[ind][k].dist;
pre[v]=ind;
if(!vis[v]){
vis[v]=1;
cout<<v<<",";
pq.push((Node){v,d[v]});
}
}
}
cout<<endl;
for(int i=1;i<=N;i++) cout<<d[i]<<",";
cout<<endl;
}
}
将每次取出的最短距离放入一个优先队列,每次从优先队列中取出
队首元素ind,对它所到达的节点进行更新。
然而这会造成多个相同节点 在队列中,但是这样带来的问题是,队列中间消耗可能会很大。这里是个坑,需要详细讲解,看下图:
首先从 1 开始
队列 1
dis 0
队列 2 4 3
dis 5 15 17
2 出队,更新
队列 4 3
dis 15 11
接下来出队的是3么?很遗憾,并不是想象中的3,请看打印结果:
为什么是4呢?
只有在对队列进行操作的时候(push 、pop),才会改变队列结构。
优先队列不是一个服务器,随时都在监测这你的 d 数组有没有值的改动。
这里面涉及到 stl 优先队列的实现,很多细节上的东西我们无从而知。
要想达到我们取出3的效果,就需要把更新过的3重新入队。
代码如下:
void dijkstra_queue2(){
priority_queue< Node>pq;
pq.push((Node){1,0});
d[1]=0;
for(int i=2;i<=N;i++) d[i]=inf;
while(!pq.empty()){
int ind=(int)pq.top().v;
pq.pop();
cout<<"出队元素"<<ind<<endl;
cout<<"入队元素";
for(int k=0;k<G[ind].size();k++){
int v=(int)G[ind][k].v;
if(v!=-1&&d[v]>d[ind]+(int)G[ind][k].dist){
d[v]=d[ind]+(int)G[ind][k].dist;
pre[v]=ind;
pq.push((Node){v,d[v]});
cout<<v<<",";
}
}
cout<<endl;
for(int i=1;i<=N;i++) cout<<d[i]<<",";
cout<<endl;
}
}
打印结果:
事实上这样 用priority queue 意义并不大。最好的方式是用堆优化dijkstra,可以每次主动去自己调整堆的结构。