观光
题目
思路
最短路计数的拓展,和拯救大兵瑞恩一样,需要我们拆点,然后在对拆后的点进行Dijkstra, 将一个点的状态拆为最短距离和次短距离,同样可能存在环形依赖,我们可以跑Dijkstra来进行状态的递推,对比最短路计数,我们只需要在加一个次短路的状态,每次状态更新的时候,如果当前点能够更新最短距离树深层的节点,我们将他放入优先队列。设\(dist[x][1/0]\)分别表示从源点\(S \rightarrow s\)的最短距离和次短距离,那么我们考虑Dijkstra的时候进行状态的更新
\[dist[x][0] \ge val + w[i]: \newline
(最短路退化为次短路) 将0的状态转移到1 \newline
更新dist[x][0]和cnt[x][0] \newline
两个都压入堆中更新下面的节点 \newline
elif \space dist[x][0] = val + w[i]: \newline
只更新cnt[x][0], 由于dist没有更新不会更新下面的点 \newline
elif \space dist[x][1] \ge val + w[i]: \newline
如果次短路可更新,用上面点的次短路更新该点的次短路 \newline
elif \space dist[x][1] = val + w[i] \newline
更新cnt[x][1]
\]
Code
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using i64 = long long;
const int N = 1e3 + 10, M = 2e4 + 10;
int n, m, dist[N][2], cnt[N][2];
bool st[N][2];
int h[N], ne[M], w[M], e[M], idx;
int S, T;
void add(int a, int b, int c) {
ne[idx] = h[a], h[a] = idx, e[idx] = b, w[idx ++] = c;
}
struct Ver {
int x, type, val;
bool operator>(const Ver &b) const {
return val > b.val;
}
};
int dijkstra() {
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
memset(cnt, 0, sizeof cnt);
std::priority_queue<Ver, std::vector<Ver>, std::greater<Ver>> h1;
h1.push({S, 0, 0});
dist[S][0] = 0;
cnt[S][0] = 1;
while (h1.size()) {
Ver t = h1.top(); h1.pop();
int x = t.x, type = t.type, val = t.val, count = cnt[x][type];
if (st[x][type]) continue;
st[x][type] = true;
for (int i = h[x]; ~i; i = ne[i]) {
int v = e[i];
if (dist[v][0] > val + w[i]) {
dist[v][1] = dist[v][0], cnt[v][1] = cnt[v][0];
h1.push({v, 1, dist[v][1]});
dist[v][0] = val + w[i], cnt[v][0] = count;
h1.push({v, 0, dist[v][0]});
} else if (dist[v][0] == val + w[i]) {
cnt[v][0] += count;
} else if (dist[v][1] > val + w[i]) {
dist[v][1] = val + w[i], cnt[v][1] = count;
h1.push({v, 1, dist[v][1]});
} else if (dist[v][1] == val + w[i]) {
cnt[v][1] += count;
}
}
}
int res = cnt[T][0];
if (dist[T][0] + 1 == dist[T][1]) res += cnt[T][1];
return res;
}
void solve() {
memset(h, -1, sizeof h);
idx = 0;
std::cin >> n >> m;
for (int i = 1; i <= m; i ++) {
int a, b, l;
std::cin >> a >> b >> l;
add(a, b, l);
}
std::cin >> S >> T;
std::cout << dijkstra() << "\n";
}
int main() {
int _;
std::cin >> _;
while (_ --) {
solve();
}
}