图论$\cdot$最短路问题
- Dijkstra单源最短路径算法
Dijkstra可以计算出发点到每个点的最短路,及单源最短路径(SSSP)。这一特点使得Dijkstra常常用来进行其他算法的预处理。用Dijkstra算法计算最短路的代码如下:
注:代码注释参见《算法竞赛入门经典——训练指南》(刘汝佳)
1 struct Dijkstra{ 2 int n, m; 3 vector<E> e; 4 vector<int> G[maxn]; 5 bool done[maxn]; 6 int d[maxn]; 7 int p[maxn]; 8 void init(int n){ 9 this->n = n; 10 FOR(i, 0, n - 1) G[i].clear(); 11 e.clear(); 12 } 13 void addE(int from, int to, int dist){ 14 e.pb(E(from, to, dist)); 15 m = e.size(); 16 G[from].pb(m - 1); 17 } 18 void dijkstra(int s){ 19 priority_queue<HeapNode> Q; 20 FOR(i, 0, n - 1) d[i] = int_inf; 21 d[s] = 0; 22 clr(done, 0); 23 Q.push(HeapNode(0, s)); 24 while(!Q.empty()){ 25 HeapNode x = Q.top(); Q.pop(); 26 int u = x.u; 27 if(done[u]) continue; 28 done[u] = 1; 29 int sz = G[u].size(); 30 FOR(i, 0, sz - 1){ 31 E &y = e[G[u][i]]; 32 if(d[y.to] > d[u] + y.dist){ 33 d[y.to] = d[u] + y.dist; 34 p[y.to] = G[u][i]; 35 Q.push(HeapNode(d[y.to], y.to)); 36 } 37 } 38 } 39 } 40 };
- Bellman-Ford算法
Bellman-Ford算法的一个重要应用是判负圈。在迭代$n-1$次后如果还可以进行松弛(relax)操作,说明一定存在负圈。如果采用队列实现,那么当某个结点入队了$n$次时可以判断出存在负圈,代码如下:
1 struct Bellman_Ford{ 2 int n, m; 3 vector<E> e; 4 vector<int> G[maxn]; 5 bool inq[maxn]; 6 int d[maxn]; 7 int p[maxn]; 8 int cnt[maxn]; 9 void init(int n){ 10 this->n = n; 11 FOR(i, 0, n - 1) G[i].clear(); 12 e.clear(); 13 } 14 void addE(int from, int to, int dist){ 15 e.pb(E(from, to, dist)); 16 m = e.size(); 17 G[from].pb(m - 1); 18 } 19 bool negCyc(){ 20 queue<int> Q; 21 clr(inq, 0), clr(cnt, 0); 22 FOR(i, 0, n - 1) d[i] = 0, inq[i] = 1, Q.push(i); 23 while(!Q.empty()){ 24 int u = Q.front(); Q.pop(); 25 inq[u] = 0; 26 int sz = G[u].size(); 27 FOR(i, 0, sz - 1){ 28 E &y = e[G[u][i]]; 29 if(d[y.to] > d[u] + y.dist){ 30 d[y].to = d[u] + y.dist; 31 p[e.to] = G[u][i]; 32 if(!inq[y.to]){ 33 Q.push(y.to); 34 inq[y.to] = 1; 35 if(++cnt[y.to] > n) return 1; 36 } 37 } 38 } 39 } 40 return 0; 41 } 42 };