Dijstra算法求单源点最短路,复杂度为O(n*n+m),用优先级队列优化后为O(n*logn).
首先建立一个集合S,当所有的点都在集合S中时,则算法结束.
1.找不在S集合中的点与s有最短距离的点m
2.更新.dis[m]=min(dis[m]+map[m][i],dis[i]),pre[i]=m;
这里写了下不完全的代码。
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
void Dijstra()
{
//初始化
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=INF;
}
init();//输入
bool S[maxn];//标记S集合的点
for(int i=1;i<=n;i++)//初始化每个点的最初距离,和前驱
{
dis[i]=map[s][i];//距离为最初值
S[i]=0;//最初都不在S集合中
if(dis[i]==INF)
pre[i]=-1;
else
pre[i]=s;
}
S[s]=1;
dis[s]=0;
for(int j=2;j<=n;j++)//只要遍历n-1次,只有n-1个点
{
//找不在S集合中的点与s的最短距离
int mindis=INF;
int m=s;
for(int i=1;i<=n;i++)
{
if(!S[i]&&dis[i]!=INF)//i不在S集合中,dis[i]不为INF
{
if(dis[i]<mindis)
{
mindis=dis[i];
m=i;
}
}
}
//mindis,m
S[m]=1;
//更新距离
for(int i=1;i<=n;i++)
{
if(map[m][i]<INF&&!S[i])
{
if(dis[m]+map[m][i]<dis[i])
{
dis[i]=dis[m]+map[m][i];
pre[i]=m;
}
}
}
}
//dis[e],path
}
void Printpath()
{
stack<int> q;
q.push(e);
int u=e;
while(u!=s)
{
q.push(u);
u=pre[u];
}
cout<<s;
while(!empty())
{
cout<<' '<<q.top();
q.pop();
}
cout<<endl;
}
int main()
{
init();
Dijstra();
Printpath();
return 0;
}
用优先级队列优化后复杂度为O(n*logn)的代码。
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
int n,m;
struct edg
{
friend bool operator<(edg x,edg y)
return x.l<y.l;
int v,l;
}
void init()
{
cin>>n>>m;
int u,v,c;
for(int i=0;i<m;i++)
{
cin>>u>>v>>c;
map[u][v]=c;
map[v][u]=c;
}
}
void Dijstra()
{
priority_queue<edg>p;
//初始化
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=INF;
}
init();//输入
bool S[maxn];//标记S集合的点
for(int i=1;i<=n;i++)//初始化每个点的最初距离,和前驱
{
dis[i]=map[s][i];//距离为最初值
edg temp; //<1>这里把每个点与源点s的边都入队
temp.l=dis[i];
temp.v=i;
p.push(temp);
S[i]=0;//最初都不在S集合中
if(dis[i]==INF)
pre[i]=-1;
else
pre[i]=s;
}
S[s]=1;
dis[s]=0;
for(int j=2;j<=n;j++)//只要遍历n-1次,只有n-1个点
{
//找不在S集合中的点与s的最短距离
/*
int mindis=INF;
int m=s;
for(int i=1;i<=n;i++)
{
if(!S[i]&&dis[i]!=INF)//i不在S集合中,dis[i]不为INF
{
if(dis[i]<mindis)
{
mindis=dis[i];
m=i;
}
}
}
//mindis,m
*/
S[m]=1;
edg q=p.top(); //<2>取最短的边
p.pop();
int mindis=q.l;
int m=q.v;
//更新距离
for(int i=1;i<=n;i++)
{
if(map[m][i]<INF&&!S[i])
{
if(dis[m]+map[m][i]<dis[i])
{
dis[i]=dis[m]+map[m][i];
pre[i]=m;
q.v=i,q.l=dis[i];//<3>可多次入队,把每次更新的距离都不入队
p.push(q);
}
}
}
}
//dis[e],path
}
void Printpath()
{
stack<int> q;
q.push(e);
int u=e;
while(u!=s)
{
q.push(u);
u=pre[u];
}
cout<<s;
while(!empty())
{
cout<<' '<<q.top();
q.pop();
}
cout<<endl;
}
int main()
{
Dijstra();
Printpath();
return 0;
}