Dijkstra算法实现最短路径
问题描述
若用有向网表示某地区的公路交通网,其中顶点表示该地区的一些主要场所,弧表示已有的公交线路,弧上的权表示票价。试设计一个交通咨询系统,指导乘客以最少花费从该地区中的某一场所到达另一场所。
基本要求
(1) 从文件中读入有向网中顶点的数量和顶点间的票价的矩阵。
(2) 以用户指定的起点和终点,输出从起点到终点的花费。
测试数据
输入
(文件)
5
-1 10 3 20 -1
-1 -1 -1 5 -1
-1 2 -1 -1 15
-1 -1 -1 -1 11
-1 -1 -1 -1 -1
(用户)
起点0
终点4
输出
18
实现提示
(1) 设图的顶点大于1个,不超过30个,每个顶点用一个编号表示(如果一个图有n个顶点,则它们的编号分别为0, 1, 2, 3, …, n-1)。
(2) 此题为求有向网中顶点间最短路径问题,可建立以票价为权的邻接矩阵,用Dijkstra算法求最短路径长度。
(3) Dijkstra算法中有一个辅助向量D,表示当前所找到的从源点到其它点的最短路径长度。因为每次都要在D中找最小值,为提高性能,用最小值堆的优先队列存储D值。
(4) 考虑没有路径时的输出。
选作内容
(1) 以用户指定的起点,输出到其它各点的花费。
(2) 以用户指定的起点和终点,输出从起点到终点的花费以及路径(经过的中间顶点)。
必做
1 #include<iostream> 2 #include<fstream> 3 #include<stdio.h> 4 #include<stdlib.h> 5 #include<string.h> 6 #include<string> 7 #define maxSize 100 8 #define maxint 1000 9 typedef enum{ FALSE, TRUE }Boolean; 10 Boolean visited[maxSize]; 11 using namespace std; 12 int read(int graph[][maxSize]) 13 { 14 FILE *in; 15 in=fopen("path","r"); 16 int n,i,j,num; 17 fscanf(in,"%d",&n); 18 19 for(i=0;i<n;i++) 20 { 21 for(j=0;j<n;j++) 22 { 23 fscanf(in,"%d",&num); 24 if(num==-1) 25 num=maxint; 26 graph[i][j]=num; 27 } 28 } 29 30 31 fclose(in); 32 return n; 33 } 34 int first(int v,int n,int graph[maxSize][maxSize]) 35 { 36 int j; 37 int ret; 38 for(j=1;j<n;j++) 39 { 40 if(graph[v][j]!=-1) 41 {return j;break;} 42 } 43 if(j==n) 44 return n; 45 } 46 int next(int v,int w,int n,int graph[maxSize][maxSize]) 47 { 48 int j; 49 for(j=w+1;j<n;j++) 50 { 51 if(graph[v][j]!=-1) 52 {return j;break;} 53 } 54 if(j==n) 55 return n; 56 } 57 int minn(int *dist,int n,int v) 58 { 59 int j,mi; 60 61 for(j=0;j<n;j++) 62 { 63 if(dist[j]!=maxint&&visited[j]==FALSE) 64 {mi=j;break;} 65 } 66 if(j==n) 67 {cout<<"不存在路径"<<endl;return -1;} 68 for(j++;j<n;j++) 69 { 70 if(dist[j]<dist[mi]&&dist[j]!=maxint&&visited[j]==FALSE) 71 mi=j; 72 } 73 return mi; 74 } 75 bool Dijkstra(int n, int v, int *dist, int graph[maxSize][maxSize]) 76 { 77 //找到与V相邻的最短路径的结点 78 int i,j,mi,w; 79 for(j=0;j<n;j++) 80 visited[j]=FALSE;//初始化为都没有被访问 81 for(j=0;j<n;j++) 82 {dist[j]=graph[v][j];} 83 mi=minn(dist,n,v); 84 85 visited[mi]=TRUE; 86 cout<<"mi___"<<mi<<endl; 87 i=0; 88 while(i<n-1) 89 { 90 91 92 for(j=0;j<n;j++) 93 { 94 if(dist[j]>dist[mi]+graph[mi][j]) 95 {dist[j]=dist[mi]+graph[mi][j];} 96 } 97 visited[mi]=TRUE; 98 mi=minn(dist,n,mi); 99 cout<<"mi "<<mi<<endl; 100 i++; 101 } 102 } 103 int main() 104 { 105 int graph[maxSize][maxSize],n,i,j; 106 int from,to; 107 int dis[maxSize],pre[maxSize]; 108 n=read(graph); 109 110 for(i=0;i<n;i++) 111 { 112 for(j=0;j<n;j++) 113 { 114 cout<<graph[i][j]<<" "; 115 } 116 cout<<endl; 117 } 118 cout<<"起点 :"; 119 cin>>from; 120 cout<<"终点 :"; 121 cin>>to; 122 123 Dijkstra(n,from,dis,graph); 124 for(i=0;i<n;i++) 125 cout<<dis[i]<<" "<<endl; 126 cout<< "从"<<from<<"到"<<to<<"的最短距离: "<<dis[to]<<endl; 127 return 0; 128 }
选做1
1 #include<iostream> 2 #include<fstream> 3 #include<stdio.h> 4 #include<stdlib.h> 5 #include<string.h> 6 #include<string> 7 #define maxSize 100 8 #define maxint 1000 9 typedef enum{ FALSE, TRUE }Boolean; 10 Boolean visited[maxSize]; 11 using namespace std; 12 int read(int graph[][maxSize]) 13 { 14 FILE *in; 15 in=fopen("path","r"); 16 int n,i,j,num; 17 fscanf(in,"%d",&n); 18 19 for(i=0;i<n;i++) 20 { 21 for(j=0;j<n;j++) 22 { 23 fscanf(in,"%d",&num); 24 if(num==-1) 25 num=maxint; 26 graph[i][j]=num; 27 } 28 } 29 30 31 fclose(in); 32 return n; 33 } 34 int first(int v,int n,int graph[maxSize][maxSize]) 35 { 36 int j; 37 int ret; 38 for(j=1;j<n;j++) 39 { 40 if(graph[v][j]!=-1) 41 {return j;break;} 42 } 43 if(j==n) 44 return n; 45 } 46 int next(int v,int w,int n,int graph[maxSize][maxSize]) 47 { 48 int j; 49 for(j=w+1;j<n;j++) 50 { 51 if(graph[v][j]!=-1) 52 {return j;break;} 53 } 54 if(j==n) 55 return n; 56 } 57 int minn(int *dist,int n,int v) 58 { 59 int j,mi; 60 61 for(j=0;j<n;j++) 62 { 63 if(dist[j]!=maxint&&visited[j]==FALSE) 64 {mi=j;break;} 65 } 66 if(j==n) 67 { 68 //cout<<"不存在路径"<<endl; 69 return -1; 70 } 71 for(j++;j<n;j++) 72 { 73 if(dist[j]<dist[mi]&&dist[j]!=maxint&&visited[j]==FALSE) 74 mi=j; 75 } 76 return mi; 77 } 78 bool Dijkstra(int n, int v, int *dist, int graph[maxSize][maxSize]) 79 { 80 //找到与V相邻的最短路径的结点 81 int i,j,mi,w; 82 for(j=0;j<n;j++) 83 visited[j]=FALSE;//初始化为都没有被访问 84 for(j=0;j<n;j++) 85 {dist[j]=graph[v][j];} 86 mi=minn(dist,n,v); 87 88 visited[mi]=TRUE; 89 //cout<<"mi___"<<mi<<endl; 90 i=0; 91 while(i<n-1) 92 { 93 94 95 for(j=0;j<n;j++) 96 { 97 if(dist[j]>dist[mi]+graph[mi][j]) 98 {dist[j]=dist[mi]+graph[mi][j];} 99 } 100 visited[mi]=TRUE; 101 mi=minn(dist,n,mi); 102 // cout<<"mi "<<mi<<endl; 103 i++; 104 } 105 } 106 int main() 107 { 108 int graph[maxSize][maxSize],n,i,j; 109 int from,to; 110 int dis[maxSize],pre[maxSize]; 111 n=read(graph); 112 113 for(i=0;i<n;i++) 114 { 115 for(j=0;j<n;j++) 116 { 117 cout<<graph[i][j]<<" "; 118 } 119 cout<<endl; 120 } 121 cout<<"起点 :"; 122 cin>>from; 123 cout<<"终点 :"; 124 cin>>to; 125 126 Dijkstra(n,from,dis,graph); 127 for(i=0;i<n;i++) 128 cout<<"起点到点"<<i<<"的最短距离"<<dis[i]<<" "<<endl; 129 //cout<< "从"<<from+1<<"到"<<to+1<<"的最短距离: "<<dis[to]<<endl; 130 return 0; 131 }
选做2
1 /*************************************** 2 * About: 有向图的Dijkstra算法实现 3 * Author: Tanky Woo 4 * Blog: www.WuTianQi.com 5 ***************************************/ 6 7 #include <iostream> 8 #include<stdio.h> 9 using namespace std; 10 11 const int maxnum = 100; 12 const int maxint = 1000; 13 14 int read(int graph[][maxnum]) 15 { 16 FILE *in; 17 in=fopen("path","r"); 18 int n,i,j,num; 19 fscanf(in,"%d",&n); 20 21 for(i=1;i<=n;i++) 22 { 23 for(j=1;j<=n;j++) 24 { 25 fscanf(in,"%d",&num); 26 if(num==-1) 27 num=maxint; 28 graph[i][j]=num; 29 } 30 } 31 32 33 fclose(in); 34 return n; 35 } 36 37 void Dijkstra(int n, int v, int *dist, int *prev, int c[maxnum][maxnum]) 38 { 39 bool s[maxnum]; // 判断是否已存入该点到S集合中 40 for(int i=1; i<=n; ++i) 41 { 42 dist[i] = c[v][i]; 43 s[i] = 0; // 初始都未用过该点 44 if(dist[i] == maxint) 45 prev[i] = 0; 46 else 47 prev[i] = v; 48 } 49 dist[v] = 0; 50 s[v] = 1; 51 52 // 依次将未放入S集合的结点中,取dist[]最小值的结点,放入结合S中 53 // 一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度 54 for(int i=2; i<=n; ++i) 55 { 56 int tmp = maxint; 57 int u = v; 58 // 找出当前未使用的点j的dist[j]最小值 59 for(int j=1; j<=n; ++j) 60 if((!s[j]) && dist[j]<tmp) 61 { 62 u = j; // u保存当前邻接点中距离最小的点的号码 63 tmp = dist[j]; 64 } 65 s[u] = 1; // 表示u点已存入S集合中 66 67 // 更新dist 68 for(int j=1; j<=n; ++j) 69 if((!s[j]) && c[u][j]<maxint) 70 { 71 int newdist = dist[u] + c[u][j]; 72 if(newdist < dist[j]) 73 { 74 dist[j] = newdist; 75 prev[j] = u; 76 } 77 } 78 } 79 } 80 81 void searchPath(int *prev,int v, int u) 82 { 83 int que[maxnum]; 84 int tot = 1; 85 que[tot] = u; 86 tot++; 87 int tmp = prev[u]; 88 while(tmp != v) 89 { 90 que[tot] = tmp; 91 tot++; 92 tmp = prev[tmp]; 93 } 94 que[tot] = v; 95 for(int i=tot; i>=1; --i) 96 if(i != 1) 97 cout << que[i] << " -> "; 98 else 99 cout << que[i] << endl; 100 } 101 102 int main() 103 { 104 105 //freopen("input.txt", "r", stdin); 106 // 各数组都从下标1开始 107 int dist[maxnum]; // 表示当前点到源点的最短路径长度 108 int prev[maxnum]; // 记录当前点的前一个结点 109 int graph[maxnum][maxnum]; // 记录图的两点间路径长度 110 int n; 111 n=read(graph); 112 113 114 for(int i=1; i<=n; ++i) 115 dist[i] = maxint; 116 for(int i=1; i<=n; ++i) 117 { 118 for(int j=1; j<=n; ++j) 119 cout<<graph[i][j]<<" "; 120 cout<<endl; 121 } 122 int from,to; 123 cout<<"起点:"; 124 cin>>from; 125 cout<<"终点:"; 126 cin>>to; 127 Dijkstra(n, from+1, dist, prev, graph); 128 129 // 最短路径长度 130 cout << "起点到终点的最短路径长度: " << dist[to+1] << endl; 131 132 // 路径 133 cout << "起点到终点的路径为: "; 134 searchPath(prev, from+1, to+1); 135 }
文件名是path 二进制文件