这篇博文主要讲述了最短路算法中
可能会用得到的建图技巧
隐式图Dijkstra
隐式图 Dijkstra \text{Dijkstra} Dijkstra 的核心在于,一边 Dijkstra \text{Dijkstra} Dijkstra 一边建图
∀ u ∈ V ( G ) , u \forall u \in V(G), u ∀ u ∈ V ( G ) , u 一般情况表示状态编码
algorithm \textbf{algorithm} algorithm
u(state, dist) \textbf{u(state,} \ \textbf{dist)} u(state, dist)
get start status \text{get start status} get start status
que ← st(stateCode, 0) \text{que}\leftarrow\text{st(stateCode, 0)} que ← st(stateCode, 0)
while(que.size()) \textbf{while(que.size())} while(que.size())
get u = que.front(), que.pop() \text{get u = que.front(), que.pop()} get u = que.front(), que.pop()
if u = endState, return D(u) \text{if u = endState, return } \textbf{D(u)} if u = endState, return D(u)
for ∀ i ∈ candidates \textbf{for} \ \forall i \in \text{candidates} for ∀ i ∈ candidates
~~~~~~ check ( e d g e s ( i ) ) is available? \text{check}(edges(i)) \text{ is available?} check ( e d g e s ( i ) ) is available?
~~~~~~ if(check == false and not available) c o n t i n u e \text{if(check == false and not available) } continue if(check == false and not available) c o n t i n u e
~~~~~~ get v(newState , u.dist + e(u, v)) \text{get } \textbf{v(newState} \ \textbf{,} \ \textbf{u.dist} \ + \textbf{e(u,} \ \textbf{v))} get v(newState , u.dist + e(u, v))
~~~~~~ sometimes change v.state \text{sometimes change v.state} sometimes change v.state
~~~~~~ D ( v ) = min ( D ( v ) , v . d i s t ) D(v) = \min(D(v), v.dist) D ( v ) = min ( D ( v ) , v . d i s t )
~~~~~~ ~~~~ if changed, que.push ( v ) \text{if changed, que.push}(v) if changed, que.push ( v )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 const int maxn = 20; const int maxm = 100 + 5; const int inf = 0x3f3f3f3f; int T[maxm]; int n, m; // == node definition == class Node { public: int state, dist; bool operator< (const Node& rhs) const { return dist > rhs.dist; } Node () {} Node(int s, int d) : state(s), dist(d) {} }; int D[1<<maxn], vis[1<<maxn ]; char before[maxm][maxn], after[maxm][maxn]; void initG () { Set(D, inf); Set(vis, 0); } // == node finished == // == Dijkstra == bool valid(const Node& u, const int k) { // check before patches k _for(i, 0, n) { if (before[k][i] == '-' && ((1<<i) & u.state)) return false; if(before[k][i ] == '+' && !((1<<i) & u.state)) return false; } return true; } int dijkstra() { priority_queue<Node> que; Node st((1<<n)-1, 0); que.push(st); D[st.state] = 0; while (!que.empty()) { Node x = que.top(); que.pop(); if(x.state == 0) return D[x.state]; if(vis[x.state]) continue; vis[x.state] = 1; // get next y _rep(i , 1, m) { bool patchable = valid(x, i); if (!patchable) continue ; // use patches i Node y(x.state, x.dist + T[i]); _for(j, 0, n) { if (after[i][j] == '+' ) y.state |= (1<<j); if(after[i][j ] == '-' ) y.state &= ~(1<<j); } if(D[y.state] > y.dist) { D[y.state] = y.dist; que.push(y); } } } return -1; } // == Dijkstra finsihed == int main() { freopen("input.txt", "r", stdin); int kase = 0; while (scanf("%d%d", &n, &m) == 2 && n) { initG(); _rep(i, 1, m) scanf("%d%s%s", &T[i], before[i], after[i]); printf("Product %d\n", ++kase); // then solve the problem int ans = dijkstra(); if(ans < 0) printf("Bugs cannot be fixed.\n\n"); else printf("Fastest sequence takes %d seconds.\n\n", ans); } }
状态依赖的Dijkstra
如果边加入一个时间维度,规定在某个时间段内可以走
∀ e ∈ E ( G ) \forall e \in E(G) ∀ e ∈ E ( G )
[ 0 , a ] : = pass \quad [0, a]:= \text{pass} [ 0 , a ] : = pass
[ a + 1 , a + b ] : = can not pass \quad [a+1, a+b]:= \text{can not pass} [ a + 1 , a + b ] : = can not pass
algorithm \textbf{algorithm} algorithm
u(id, dist) , D ( V ) = ∞ \textbf{u(id,} \ \textbf{dist)}, D(V)=\infty u(id, dist) , D ( V ) = ∞
get st \text{get st} get st
que ← st(s, 0), D(s) = 0 \text{que} \leftarrow\text{st(s, 0), D(s) = 0} que ← st(s, 0), D(s) = 0
while(que.size()) \textbf{while(que.size())} while(que.size())
~~~~~~ get u = que.front(), que.pop() \text{get u = que.front(), que.pop()} get u = que.front(), que.pop()
~~~~~~ check ∀ e ( u , v ) ∈ E ( G ) \text{check } \forall e(u, v) \in E(G) check ∀ e ( u , v ) ∈ E ( G )
~~~~~~ if e . t > e . a , could not pass, c o n t i n u e \text{if } e.t > e.a, \text{could not pass, } continue if e . t > e . a , could not pass, c o n t i n u e
~~~~~~ for ∀ e ( u , v ) \textbf{for} \ \forall e(u, v) for ∀ e ( u , v )
~~~~~~ ~~~~ check D ( u ) ⟷ ? [ 0 , e . a ] ∪ [ e . a + 1 , e . a + e . b ] \textbf{check}\ D(u) \stackrel{?}\longleftrightarrow [0,e.a] \cup [e.a+1, e.a+e.b] check D ( u ) ⟷ ? [ 0 , e . a ] ∪ [ e . a + 1 , e . a + e . b ]
~~~~~~ ~~~~ D ( u ) ≡ r ( m o d e . a + e . b ) D(u) \equiv r \pmod{e.a+e.b} D ( u ) ≡ r ( m o d e . a + e . b )
~~~~~~ ~~~~ r + e . t ∈ [ 0 , e . a ] , w ( u , v ) : = e . t r + e.t \in [0, e.a], \quad w(u, v):= e.t r + e . t ∈ [ 0 , e . a ] , w ( u , v ) : = e . t
~~~~~~ ~~~~ r + e . t > e . a , w ( u , v ) : = ( e . a + e . b − r ) + e . t r+e.t > e.a, \quad w(u, v):= (e.a+e.b-r) + e.t r + e . t > e . a , w ( u , v ) : = ( e . a + e . b − r ) + e . t
~~~~~~ ~~~~ D ( v ) = min ( D ( v ) , D ( u ) + w ) D(v) = \min(D(v), D(u) + w) D ( v ) = min ( D ( v ) , D ( u ) + w )
~~~~~~ ~~~~~~~~ if changed, que ← v \text{if changed, que} \leftarrow v if changed, que ← v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 const int maxn = 300 + 10; const int inf = 0x3f3f3f3f; int n, m, s, t; int D[maxn], vis[maxn]; // == Graph definition == vector<int> G[maxn]; class Edge { public: int from, to, a, b, t; Edge(int from, int to, int a, int b, int t) : from(from), to(to), a(a), b(b), t(t) {} Edge () {} }; vector<Edge> edges; void addEdge(int u, int v, int a, int b, int t) { edges.push_back(Edge(u, v, a, b, t)); G[u].push_back(edges.size() - 1); } void initG(int s) { Set(D, inf); D[s] = 0; Set(vis, 0); } // == Graph finished == // == Dijkstra == struct Node { int u, dist; Node(int u, int d) : u(u), dist(d) {} Node () {} bool operator< (const Node& rhs) const { return dist > rhs.dist; } }; void dijkstra(int s) { priority_queue<Node> que; que.push(Node(s, 0)); while (!que.empty()) { int x = que.top().u; que.pop(); if (vis[x]) continue ; vis[x] = true ; _for(i, 0, G[x].size()) { const Edge& e = edges[G[x][i]]; int y = e.to; if (e.t > e.a) continue ; int w, r = D[x] % (e.a + e.b); if (r + e.t <= e.a) w = e.t; else w = e.a + e.b - r + e.t; if (D[y] > D[x] + w) { D[y] = D[x] + w; que.push(Node(y, D[y])); } } } } // == Dijkstra finished == void init () { _rep(i, 0, n) G[i].clear(); edges.clear(); } int main () { freopen("input.txt" , "r" , stdin); int kase = 0; while (~scanf("%d%d%d%d" , &n, &m, &s, &t)) { init(); printf ("Case %d: " , ++kase); // get data _for(i, 0, m) { int u, v, a, b, t; scanf("%d%d%d%d%d" , &u, &v, &a, &b, &t); addEdge(u, v, a, b, t); } // then dijkstra initG(s); dijkstra(s); printf ("%d\n" , D[t]); } }
动态规划统计最短路条数
algorithm \textbf{algorithm} algorithm
run Dijkstra() and calculate ∀ u ∈ V ( G ) → D ( u ) \text{run} \ \textbf{Dijkstra()} \ \text{and calculate } \forall u \in V(G) \rightarrow D(u) run Dijkstra() and calculate ∀ u ∈ V ( G ) → D ( u )
f ( k , u ) f(k, u) f ( k , u ) 表示以 D ( u ) + k D(u)+k D ( u ) + k 作为最短路的路径条数
~~~~~~ [ D ( u ) , k ] [D(u), k] [ D ( u ) , k ] 表示此时的 u u u 点的长度为 D ( u ) + k D(u) + k D ( u ) + k
~~~~~~ ∀ e ( u , v ) : = \forall e(u, v) := ∀ e ( u , v ) : =
[ D ( u ) , k ] ⇒ { { f ( 1 , v ) + = f ( 0 , u ) } ∪ { f ( k , v ) + = f ( k , u ) } , k = 0 { f ( k , v ) + = f ( k , u ) } , k = 1 \begin{gathered}
[D(u),k]\Rightarrow\left\{\begin{array}{lc}
\{f(1, v)+=f(0, u)\} \cup \{f(k, v)+=f(k, u)\}, \quad k=0 \\
\{f(k, v)+=f(k, u)\} , \quad k = 1
\end{array}\right.
\end{gathered}
[ D ( u ) , k ] ⇒ { { f ( 1 , v ) + = f ( 0 , u ) } ∪ { f ( k , v ) + = f ( k , u ) } , k = 0 { f ( k , v ) + = f ( k , u ) } , k = 1
D ( v ) = D ( u ) + w ( u , v ) → f ( k , v ) + = f ( k , u ) D ( v ) + 1 = D ( u ) + w ( u , v ) → f ( 1 , v ) + = f ( 0 , u ) \begin{gathered}
D(v) = D(u) + w(u, v) \quad \rightarrow f(k, v) += f(k, u) \\
D(v)+1 = D(u) + w(u, v) \quad \rightarrow f(1, v) += f(0, u)
\end{gathered}
D ( v ) = D ( u ) + w ( u , v ) → f ( k , v ) + = f ( k , u ) D ( v ) + 1 = D ( u ) + w ( u , v ) → f ( 1 , v ) + = f ( 0 , u )
f ( 0 , s ) = 1 f(0, s) = 1
f ( 0 , s ) = 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 const int maxn = 1e3 + 10; const ll inf = 0x3f3f3f3f3f3f3f3f; int n, m, st, ed; // == Graph definition == vector<int> G[maxn]; int vis[maxn]; ll D[maxn]; class Edge { public: int to, w; Edge(int t, int w) : to(t), w(w) {} Edge () {} }; vector<Edge> edges; void addEdge(int u, int v, int w) { edges.push_back(Edge(v, w)); G[u].push_back(edges.size() - 1); } void initG(int st) { _for(i, 0, maxn) D[i] = inf; D[st] = 0; Set(vis, 0); } // == Graph finished == // == Dijkstra == struct Node { int u; ll dist; Node () {} Node(int u, ll d) : u(u), dist(d) {} bool operator< (const Node& rhs) const { return dist > rhs.dist; } }; void dijkstra(int st) { priority_queue<Node> que; que.push(Node(st, 0)); while (!que.empty()) { int x = que.top().u; que.pop(); if (vis[x]) continue ; vis[x] = true ; _for(i, 0, G[x].size()) { const Edge& e = edges[G[x][i]]; int y = e.to; if (D[y] > D[x] + 1ll * e.w) { D[y] = D[x] + 1ll * e.w; que.push(Node(y, D[y])); } } } } // == Dijkstra finished == // == dp == ll f[2][maxn]; bool cmp(int a, int b) { return D[a] < D[b]; } int ord[maxn]; void initDp () { Set(f, 0); f[0][st] = 1ll; _rep(i, 1, n) ord[i] = i; sort(ord + 1, ord + 1 + n, cmp); } void dp () { _for(k, 0, 2) _rep(i, 1, n) { int x = ord[i]; _for(j, 0, G[x].size()) { const Edge& e = edges[G[x][j]]; int y = e.to; if (D[y] == D[x] + e.w) f[k][y] += f[k][x]; if (k == 0 && D[y] + 1 == D[x] + e.w) f[1][y] += f[0][x]; } } } // == dp finsiehd == void init () { _for(i, 0, maxn) G[i].clear(); edges.clear(); } int main () { freopen("input.txt" , "r" , stdin); int kase; scanf("%d" , &kase); while (kase--) { init(); scanf("%d%d" , &n, &m); // input data _for(i, 0, m) { int u, v, l; scanf("%d%d%d" , &u, &v, &l); addEdge(u, v, l); } scanf("%d%d" , &st, &ed); // dijkstra initG(st); dijkstra(st); // then dp initDp(); dp(); printf ("%lld\n" , f[0][ed] + f[1][ed]); } }