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; }