Dijkstra——单源最短路径

来源:互联网 发布:黑色梦中 知乎 编辑:程序博客网 时间:2024/05/29 12:32
/*
Dijkstra算法:
1.将所有的顶点分为两部分:已知最短路程的顶点集合P未知最短路径的顶点集合Q
  最开始,已知最短路径的定点集合P中只有源点一个顶点。用visit数组记录哪些顶点在P中。
  对于某个顶点i,如果visit[i]为1则表示此顶点在P中,若visit[i]为0,则表示此顶点在集合Q中
  
2.设置源点v到自己的最短路径为0,即dis[v]=0。若存在源点能直接到达的顶点i,则把dis[i]设为e[v][i]
  同时把所有其他(源点不能直接到达的)顶点的最短路径设为inf(无穷大)
  
3.在集合Q中所有的顶点中选择一个离源点v最近的顶点u(即dis[u]最小),加入到集合P
  并考察所有以u为起点的边,对每一条边进行松弛操作。
  如果存在一条从u到s的边,可以通过将边u->s添加到尾部来拓展一条从v到s的路径,这条路径的长度是dis[u]+e[u][s].
  如果这个值比目前已知的dis[s]的值要小,则可以用新值来替代当前dis[s]中的值。
  
4.重复第3步,直到集合Q为空,算法结束。最终dis数组中的值就是源点到所有顶点的完整路径。 

*/ 

#include<iostream>#define maxnum 100#define inf 999999using namespace std;void Dijkstra(int n,int v,int *dis,int *prev,int c[maxnum][maxnum]){bool visit[maxnum];//判断该点是否已经存入集合S中 //初始化 for(int i=1;i<=n;i++){dis[i]=c[v][i];visit[i]=0;//初始都未使用过该点if(dis[i]==inf)prev[i]=0;else prev[i]=v;}dis[v]=0;visit[v]=1;for(int i=2;i<=n;i++){int min=inf;int u=v;//找出当前未使用点j的dis[j]最小值for(int j=1;j<=n;j++)if(!visit[j]&&dis[j]<min){u=j;//u保存当前邻接点中距离最小点的标号 min=dis[j];}visit[u]=1;//表示u点已经存入集合P中 //更新disfor(int j=1;j<=n;j++)if(!visit[j]&&c[u][j]<inf){if(dis[u]+c[u][j]<dis[j]){//松弛操作dis[j]=dis[u]+c[u][j];prev[j]=u;}} }}void showPath(int *prev,int v,int u){int que[maxnum];int tot=1;que[tot]=u;tot++;int tmp=prev[u];while(tmp!=v){que[tot]=tmp;tot++;tmp=prev[tmp];}que[tot]=v;for(int i=tot;i>=1;i--){if(i!=1)cout<<que[i]<<"->";elsecout<<que[i]<<endl;}}int main(){freopen("input1.txt","r",stdin);int dis[maxnum];int prev[maxnum];int c[maxnum][maxnum];int n,m;cin>>n;cin>>m;int p,q,w;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)c[i][j]=inf;for(int i=1;i<=m;i++){cin>>p>>q>>w;if(w<c[p][q]){c[p][q]=w;c[q][p]=w;}}for(int i=1;i<=n;i++)dis[i]=inf;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%8d",c[i][j]);printf("\n");}Dijkstra(n,1,dis,prev,c);//最短路径长度    cout << "源点到最后一个顶点的最短路径长度: " << dis[n] << endl;//路径    cout << "源点到最后一个顶点的路径为: ";    showPath(prev,1,n);}


原创粉丝点击