Dijkstra算法
问题描述:【单源最短路径问题】给定一个带权图(无负权)和一个指定的顶点V0,求出V0到所有其他各点的最短路径。
算法过程:
本质也是个贪心算法。
① 所有顶点划分为两个集合S和D。初始S集合只有点V0,V0对应的距离值为0;剩余的顶点皆在D集合中,如果存在边<V0,Vi>,则Vi的距离值为此边的权值,否则Vi的距离值为∞
② 从D中选择离源距离值最小的顶点Vm加入到S集合
③ 同时以Vm 作为中间顶点,更新距离值
④ 重复②③直到D为空(或最小值也为∞)
具体实现:
1.普通实现:更适合稠密图
int min[N];//记录当前最小距离
bool flag[N];//标志是否在集合S中
int pre[N];//如需要打印结点,记录前驱
用一维数组。每次扫描,如需打印路径,增加pre段记录上层。
例:POJ 1847 Tram
2.最小堆优化:比较适合稀疏图,但每次改变距离都要重排堆。
算法复杂度:O(n^2)
附:POJ1847 Tram
View Code
1 //POJ 1847 Tram Dijkstra 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 #define INF 0xfffffff 6 #define MIN(x,y) (x < y ? x : y) 7 int dis[101][101]; 8 int n; 9 10 void init_dis() 11 { 12 int t, c; 13 memset(dis, 0xf, sizeof(dis)); 14 for (int i = 1; i <= n; i++) 15 { 16 cin >> t; 17 if (t == 0) 18 continue; 19 cin >> c; 20 dis[i][c] = 0; 21 for (int j = 2; j <= t; j++) 22 { 23 cin >> c; 24 dis[i][c] = 1; 25 } 26 } 27 for (int i = 1; i <= n; i++) 28 dis[i][i] = 0; 29 } 30 31 int Dijktra(int src, int des) 32 { 33 if (src == des) return 0; 34 int minDis[101];//最小距离 35 bool flag[101]; 36 37 memset(minDis, 0xf, sizeof(minDis)); 38 memset(flag, 0, sizeof(flag)); 39 40 flag[src] = true; 41 for (int i = 1; i <= n; i++) 42 minDis[i] = dis[src][i]; 43 44 for (int j = 1; j < n; j++) 45 { 46 //取最小 47 int min = 0; 48 for (int i = 1; i <= n; i++) 49 if (!flag[i] && minDis[i] < minDis[min]) 50 min = i; 51 //判断是否取完 52 if (min == des) return minDis[min]; 53 if (min == 0) break; 54 flag[min] = true; 55 //更新最短路径长 56 for (int i = 1; i <= n; i++) 57 if (!flag[i]) 58 minDis[i] = MIN(minDis[i], minDis[min]+dis[min][i]); 59 } 60 return -1; 61 } 62 int main(void) 63 { 64 int src, des; 65 cin >> n >> src >> des; 66 init_dis(); 67 cout << Dijktra(src, des) << endl; 68 return 0; 69 }

浙公网安备 33010602011771号