You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define x first
#define y second
const int N = 1e3 + 13;
const int M = 1e6 + 10;
int n, m, u, v, s, f;
// 将最短路扩展为二维,含义:最短路与次短路
// dis:路径长度,cnt路线数量,st:是否已经出队列
int dis[N][2], 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++;
}
struct Node {
// u: 节点号
// d:目前结点v的路径长度
// k:是最短路0还是次短路1
int u, d, k;
const bool operator<(Node x) const {
return d > x.d;
}
};
void dijkrsta() {
priority_queue<Node> q; // 默认是大顶堆通过定义结构体小于号实现小顶堆。比如认证的d值更大谁就更小
memset(dis, 0x3f, sizeof dis); // 清空最小距离与次小距离数组
memset(cnt, 0, sizeof cnt); // 清空最小距离路线个数与次小距离路线个数数组
memset(st, 0, sizeof st); // 清空是否出队过数组
cnt[s][0] = 1; // 起点s0:最短路1:有一条
cnt[s][1] = 0; // 次短路路线数为0
dis[s][0] = 0; // 最短路从s出发到s的距离是0
dis[s][1] = 0; // 次短路从s出发到s的距离是0
q.push({s, 0, 0}); // 入队列
while (q.size()) {
Node x = q.top();
q.pop();
int u = x.u, k = x.k; // u:节点号k:是最短路还是次短路d:路径长度(这个主要用于堆中排序不用于实战实战中可以使用dis[u][k])
if (st[u][k]) continue; // ① 和dijkstra标准版本一样的只不过多了一个维度
st[u][k] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
int dj = dis[u][k] + w[i]; // 原长度+到节点j的边长
if (dj == dis[j][0]) // 与到j的最短长度相等则更新路径数量
cnt[j][0] += cnt[u][k];
else if (dj < dis[j][0]) { // 找到更小的路线,需要更新
dis[j][1] = dis[j][0]; // 次短距离被最短距离覆盖
cnt[j][1] = cnt[j][0]; // 次短个数被最短个数覆盖
dis[j][0] = dj; // 更新最短距离
cnt[j][0] = cnt[u][k]; // 更新最短个数
q.push({j, dis[j][1], 1}); // ②
q.push({j, dis[j][0], 0});
} else if (dj == dis[j][1]) // 如果等于次短
cnt[j][1] += cnt[u][k]; // 更新次短的方案数,累加
else if (dj < dis[j][1]) { // 如果大于最短,小于次短,两者中间
dis[j][1] = dj; // 更新次短距离
cnt[j][1] = cnt[u][k]; // 更新次短方案数
q.push({j, dis[j][1], 1}); // 次短入队列
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("POJ3463.in", "r", stdin);
/*
答案:
3
2
*/
#endif
int T;
scanf("%d", &T);
while (T--) {
memset(h, -1, sizeof h);
scanf("%d %d", &n, &m);
while (m--) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
add(a, b, c);
}
// 起点和终点
scanf("%d %d", &s, &f);
// 计算最短路
dijkrsta();
// 输出
printf("%d\n", cnt[f][0] + (dis[f][1] == dis[f][0] + 1 ? cnt[f][1] : 0));
}
return 0;
}