以前看过SPFA的解释,看懂了却一直没有尝试着写出来。今天见到一题100000个点1000000条边的最短路问题,看到边数相对点来说是非常少的,所以我第一反应就是用Dij来做。但是考虑到普通的Dij写这个10^6条边的代码是带不动的,于是我突然想起了好像可以用优先队列来对此优化,这种优化方法叫做SPFA(纠正一下,应该说这种方法跟SPFA类似,但SPFA是对Bellman的普通队列优化)。我没有再去看SPFA的伪代码或者模板,只是凭自己对优先队列的用法来尝试着写这个优先队列优化的Dij,自己算过,理论时间复杂度是O(ke),e是边的数目,k不超过2。
由于是第一次写这个代码,中间出现好多错误,例如,忘记检查队列是否为空而直接用pop和top。
最后打完后测试了几组数据,都OK了。于是我就交上去,除了内存开销比较大,时间是相当理想的:
11876kB | 30ms |
好了,记录一下我的1Y代码吧!
View Code
1 #include "cstdio" 2 #include "cstdlib" 3 #include "cstring" 4 #include "cmath" 5 #include "cctype" 6 #include "vector" 7 #include "set" 8 #include "map" 9 #include "string" 10 #include "algorithm" 11 #include "stack" 12 #include "queue" 13 14 #define INF 0x7fffffff 15 #define reset(a) memset(a, 0, sizeof(a)) 16 #define copy(a, b) memcpy(a, b, sizeof(b)) 17 #define PI acos(-1) 18 #define FMAX (1E300) 19 #define MAX 1000000000 20 #define feq(a, b) (fabs((a)-(b))<1E-6) 21 #define flq(a, b) ((a)<(b)||feq(a, b)) 22 #define MAXN 10005 23 #define BASE 137 24 #define PASS puts("pass") 25 #define filein freopen("test.in", "r", stdin) 26 #define fileout freopen("test.out", "w", stdout) 27 28 using namespace std; 29 30 struct Point{ 31 int p; 32 int d; 33 bool operator < (const Point &x) const{ 34 return d > x.d; 35 } 36 }; 37 struct Edge{ 38 int b; 39 int e; 40 int d; 41 bool operator < (const Edge &x) const{ 42 return b < x.b; 43 } 44 bool operator == (const Edge &x) const{ 45 return b == x.b; 46 } 47 }e[1000000]; 48 priority_queue<Point, vector<Point>, less<Point> >Q; 49 int v[100001]; 50 bool vis[100001]; 51 52 int main(){ 53 int n, m; 54 //filein; 55 //fileout; 56 pair<Edge *, Edge *> p; 57 58 while (~scanf("%d%d", &n, &m)){ 59 reset(e); 60 reset(vis); 61 62 while (Q.size()) 63 Q.pop(); 64 vis[1] = true; 65 v[1] = 0; 66 for (int i = 2; i <= n; i++) 67 v[i] = MAX; 68 69 for (int i = 0; i < m; i++) 70 scanf("%d%d%d", &e[i].b, &e[i].e, &e[i].d); 71 sort(e, e + m); 72 73 int cur = 1; 74 Edge te; 75 Point tp; 76 77 tp = {1, 0}; 78 Q.push(tp); 79 while (Q.size() && cur != n){ 80 te.b = cur; 81 p = equal_range(e, e + m, te); 82 //printf("search %d %d\n", p.first - e, p.second - e); 83 for (int i = p.first - e, end = p.second - e; i < end; i++){ 84 if (v[e[i].e] > v[e[i].b] + e[i].d){ 85 v[e[i].e] = v[e[i].b] + e[i].d; 86 if (!vis[e[i].e]){ 87 tp = {e[i].e, v[e[i].e]}; 88 Q.push(tp); 89 //PASS; 90 } 91 } 92 } 93 while (Q.size() && vis[Q.top().p]){ 94 Q.pop(); 95 } 96 if (Q.size()){ 97 cur = Q.top().p; 98 vis[cur] = true; 99 Q.pop(); 100 } 101 } 102 printf("%d\n", v[n]); 103 } 104 105 return 0; 106 }
——written by Lyon