板子——SPFA/判负环
SPFA是很简单的:普通队列,用du + w更新dv即可。判断是否in queue可以提高速度。
1 void spfa() { 2 memset(d, 0x3f, sizeof d); d[1] = 0; 3 q.push(1); inq[1] = true; 4 while (!q.empty()) { 5 int u = q.front(); q.pop(); 6 inq[u] = false; //just to improve effiency 7 for (int i = 0; i < g[u].size(); i++) { 8 int v = g[u][i].v, w = g[u][i].w; 9 if (d[v] > d[u] + w) { 10 d[v] = d[u] + w; 11 if (!inq[v]) q.push(v), inq[v] = true; 12 } 13 } 14 } 15 }
这里放上Dij加以对比:利用优先队列每次找dv最小的点,而且要避免重复访问。而当负环存在时,当下最小的dv不一定以后最小,dij不再正确。
1 void dijkstra() { 2 memset(d, 0x3f, sizeof d); d[1] = 0; 3 q.push(make_pair(0, 1)); 4 while (q.size()) { 5 int u = q.top().second; q.pop(); 6 if (vis[u]) continue; 7 vis[u] = 1; 8 for (int i = 0; i < g[u].size(); i++) { 9 int v = g[u][i].v, w = g[u][i].w; 10 if (d[v] > d[u] + w) d[v] = d[u] + w, q.push(make_pair(-d[v], v)); 11 } 12 } 13 }
在SPFA中,如果从起点到某个点的当前最短路径上走过了至少n个点,说明存在负环。
1 bool spfa() { 2 memset(d, 0x3f, sizeof d); d[1] = 0; 3 for (int i = 1; i <= n; i++) { 4 q.push(i); inq[i] = 1; 5 } 6 while (!q.empty()) { 7 int u = q.front(); q.pop(); 8 inq[u] = false; 9 for (int i = 0; i < g[u].size(); i++) { 10 int v = g[u][i].v, w = g[u][i].w; 11 if (d[v] > d[u] + w) { 12 d[v] = d[u] + w; 13 cnt[v] = cnt[u] + 1; 14 if (cnt[v] >= n) return 1; 15 if (!inq[v]) q.push(v), inq[v] = 1; 16 } 17 } 18 } 19 return 0; 20 }