#include using namespace std; const int N = 1010; const int M = 10010; int n, m; int dist[N][2]; int cnt[N][2]; bool st[N][2]; // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } // 本题需要一个三个属性的对象:最短距离d,最短、次短k,id:节点号 struct Node { int d, k, id; // 小顶堆需要重载大于号,大顶堆需要重载小于号 bool const operator>(Node b) const { return d > b.d; } }; void dijkstra(int S) { memset(dist, 0x3f, sizeof dist); memset(st, false, sizeof st); memset(cnt, 0, sizeof cnt); priority_queue, greater<>> pq; // 小顶堆 dist[S][0] = 0; cnt[S][0] = 1; pq.push({0, 0, S}); while (pq.size()) { auto t = pq.top(); pq.pop(); int u = t.id; int k = t.k; if (st[u][k]) continue; st[u][k] = true; for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; int d = dist[u][k] + w[i]; if (dist[v][0] > d) { // 比最短路还要短 dist[v][1] = dist[v][0]; // 最短降为次短 cnt[v][1] = cnt[v][0]; // 次短路数量被更新 pq.push({dist[v][1], 1, v}); // 次短被更新,次短入队列 dist[v][0] = d; // 替换最短路 cnt[v][0] = cnt[u][k]; // 替换最短路数量 pq.push({dist[v][0], 0, v}); // 最短路入队列 } else if (dist[v][0] == d) // 增加最短路的数量 cnt[v][0] += cnt[u][k]; else if (dist[v][1] > d) { // 替换次短路 dist[v][1] = d; cnt[v][1] = cnt[u][k]; pq.push({dist[v][1], 1, v}); // 次短路入队列 } else if (dist[v][1] == d) cnt[v][1] += cnt[u][k]; } } } int main() { int T; scanf("%d", &T); while (T--) { scanf("%d %d", &n, &m); memset(h, -1, sizeof h); idx = 0; while (m--) { int a, b, c; scanf("%d %d %d", &a, &b, &c); add(a, b, c); } int S, F; scanf("%d %d", &S, &F); dijkstra(S); int ans = cnt[F][0]; // 最短路 // 在正常处理完最短路和次短路后,在最后的逻辑中,增加本题的中特殊要求部分 if (dist[F][0] == dist[F][1] - 1) ans += cnt[F][1]; printf("%d\n", ans); } return 0; }