迪杰斯特拉算法用于求解单源最短路问题,能求解出从一个点出发到剩余所有节点的最短距离。
原理:
使用贪心选择,将全部节点分为两部分,已经找出最短路径的点和没有为找出最短路径的点,初始情况下源点为唯一一个找出最短距离的点,每次从未找出最短路径的点中选中距离源点最近的点设置为已经找到最短路径的点并记录下相应的最短距离。
具体过程:
算法的时间瓶颈在于怎么获得一个节点到源点的距离和查找出距离最短的点的编号。
解决方法是花额外的空间定义一个lowdis数组代表对应下标的节点到源点的最短距离。初始化时如果一个节点和源点是直接连通的,则对应元素初始化为相应的道路长度,否则初始化为无限大INF,每次从中选出值最小的节点,然后更新lowdis数组,更新的原因是再加入一个新的节点后可能存在lowdis[i]>lowdis[minn]+dis[minn][i]的情况,其中minn就是新找到最短距离的节点的编号,也就是当前节点取道minn节点可能会更近。
如果要统计最短路径节点信息,可以再添加一个last数组,存放每个节点的上一个节点编号,最后再倒序输出就行。
示例代码:给出一个图的信息,求从一个点到另外一个点的最短距离和最短路径。
- #include<iostream>
- #include<cstring>
- #include<stack>
- using namespace std;
- #define MaxN 100
- #define INF 99999
- int dis[MaxN][MaxN]; //存放亮点间距离
- int last[MaxN]; //存放每个节点的上一个节点
- int N; //存放节点数量
- int search(int START,int END){ //迪杰斯特拉算法
- bool vis[MaxN]={0}; //标记访问情况
- vis[START]=true;
- int lowdis[MaxN];
- for(int i=0;i<=N;i++){
- lowdis[i]=dis[START][i];
- last[i]=START;
- }
- int min,minn;
- for(int i=1;i<N;i++){
- min=INF;
- for(int j=1;j<=N;j++){
- if(vis[j]==0){
- if(lowdis[j]<min){
- min=lowdis[j];
- minn=j;
- }
- }
- }
- if(min<INF){
- vis[minn]=true;
- for(int j=0;j<=N;j++){ //更新lowdis数组
- if(lowdis[j]>dis[minn][j]+lowdis[minn]){
- lowdis[j]=dis[minn][j]+lowdis[minn];
- last[j]=minn;
- }
- }
- }
- else return -1;
- }
- return lowdis[END];
- }
- void showway(int START,int END){ //打印最短道路信息
- stack<int> way; //利用栈来倒序输出
- way.push(END);
- int at=END;
- while(at!=START){
- way.push(last[at]);
- at=last[at];
- }
- while(!way.empty()){
- cout<<way.top()<<‘ ‘;
- way.pop();
- }
- }
- int main(){ //测试
- int M,a,b,c;
- for(int i=0;i<MaxN;i++)for(int j=0;j<MaxN;j++)dis[i][j]=dis[j][i]=INF;
- cout<<"一共有多少个地点多少条道路?"<<endl;
- cin>>N>>M;
- cout<<"输入道路信息(输入连接的两个地点编号和长度如1 2 3代表1,2间存在长度为3的道路)"<<endl;
- while(M--){
- cin>>a>>b>>c;
- dis[a][b]=dis[b][a]=c;
- }
- cout<<"从哪到哪"<<endl;
- cin>>a>>b;
- cout<<"最短距离:"<<search(a,b)<<endl;
- cout<<"最短道路:";
- showway(a,b);
- cout<<endl;
- }
附上一组简单的测试数据
5 7
1 2 3 2 3 4 3 4 5 4 5 6 1 3 1 4 1 10 1 5 99
1 5