SPFA算法(求解单源最短路)详解 + 最短路 之 CODE[VS] 1079 回家
/*
求解单源最短路问题:SPFA算法(有向加权图不存在负权回路)
参考:《数据结构与编程实验--大学生程序设计课程与竞赛训练教材》(http://book.douban.com/subject/10537877/)
弥补Dijkstra算法无法处理图中存在负权边;
弥补Bellman-Ford算法效率低。
SPFA算法类似宽度优先搜索,动态逼近法:
队列Q存储可以优化其他节点的节点,每次从队列中取出队首节点u,并用u点的dist值对
u点出边所指向的节点v进行松弛操作。如果v点的dist值有所调整且v点不在队列Q中,则
v点进入队列Q。
这样不断从队列Q中取出节点来进行松弛操作,直至Q队列为空。
时间复杂度:
在算法执行时,设k为所有节点入队的平均次数(可以证明k一般小于等于2),而每个节点
入队后需要花费O(|E|)时间对它们的所有出边进行松弛操作,
故时间复杂度:O(k*|E|)
对比Bellman-Ford算法:
相似之处(思想):
计算过程都是迭代式的,最短路径都是临时的,都采用了不断逼近最优解的贪心策略,
只有最后一步才确定想要的结果。
不同之处(实现方式):
Bellman-Ford算法:某个点最短路径估计值被更新了,那就必须对所有边的尾做一次松弛操作;
SPFA算法:某个点最短路径估计值被更新了,仅需对该点出边的端点做一次松弛操作。
----------------------------------------
CODE[VS] 1079 回家
从'Z'出发,最短路Spfa即可。
*/
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstddef> 5 #include <iterator> 6 #include <algorithm> 7 #include <string> 8 #include <locale> 9 #include <cmath> 10 #include <vector> 11 #include <cstring> 12 #include <map> 13 #include <utility> 14 #include <queue> 15 #include <stack> 16 #include <set> 17 #include <functional> 18 using namespace std; 19 typedef pair<int, int> P; 20 const int INF = 0x3f3f3f3f; 21 const int modPrime = 3046721; 22 const double eps = 1e-9; 23 const int MaxN = 60; 24 25 int n; 26 27 struct Edge 28 { 29 int to; 30 int dis; 31 }; 32 33 vector<Edge> edgeVec[MaxN]; 34 int dis[MaxN]; 35 36 int charToNum(char ch) 37 { 38 if (ch >= 'A' && ch <= 'Z') 39 { 40 // 0~25 41 return (ch - 'A'); 42 } 43 else 44 { 45 // 26~51 46 return (ch - 'a') + 26; 47 } 48 } 49 50 char numToChar(int num) 51 { 52 if (num >= 0 && num <= 25) 53 { 54 // 0~25 55 return ('A' + num); 56 } 57 else 58 { 59 // 26~51 60 return ('a' + (num - 26)); 61 } 62 } 63 64 65 void Spfa() 66 { 67 fill(dis, dis + MaxN, INF); 68 int S = charToNum('Z'); 69 dis[S] = 0; 70 71 bool isInQue[MaxN]; 72 fill(isInQue, isInQue + MaxN, false); 73 74 queue<int> que; 75 que.push(S); 76 isInQue[S] = true; 77 while (!que.empty()) 78 { 79 int node = que.front(); 80 que.pop(); 81 isInQue[node] = false; 82 Edge eg; 83 for (int i = 0; i < edgeVec[node].size(); ++i) 84 { 85 eg = edgeVec[node][i]; 86 if (dis[eg.to] > dis[node] + eg.dis) 87 { 88 dis[eg.to] = dis[node] + eg.dis; 89 if (!isInQue[eg.to]) 90 { 91 que.push(eg.to); 92 isInQue[eg.to] = true; 93 } 94 } 95 } 96 } 97 } 98 99 void Solve() 100 { 101 Spfa(); 102 int num = 0; 103 int ans = INF; 104 for (int i = 0; i < 25; ++i) 105 { 106 if (ans > dis[i]) 107 { 108 num = i; 109 ans = dis[i]; 110 } 111 } 112 cout << numToChar(num) << " " << ans << endl; 113 } 114 115 int main() 116 { 117 #ifdef HOME 118 freopen("in", "r", stdin); 119 //freopen("out", "w", stdout); 120 #endif 121 122 cin >> n; 123 Edge eg; 124 for (int i = 0; i < n; ++i) 125 { 126 char chFrom, chTo; 127 cin >> chFrom >> chTo >> eg.dis; 128 129 int ifrom = charToNum(chFrom); 130 int ito = charToNum(chTo); 131 132 eg.to = ito; 133 edgeVec[ifrom].push_back(eg); 134 eg.to = ifrom; 135 edgeVec[ito].push_back(eg); 136 } 137 Solve(); 138 139 #ifdef HOME 140 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl; 141 _CrtDumpMemoryLeaks(); 142 #endif 143 return 0; 144 }