[最短路图] Codeforces 1650G
题目大意
给定一张 \(n\) 个点 \(m\) 条边的无向图,设 \(s\) 到 \(t\) 的最短路长度为 \(x\),求 \(s\) 到 \(t\) 长度不超过 \(x+1\) 的路径条数,对 \(10^9+7\) 取模。\((n,m\leq 2\times 10^5)\)
题解
先跑一遍 dijkstra,求出最短路图。容易发现,长度比最短路长度多 \(1\) 的路径一定恰好存在一条边\((u,v)\)不在最短路图上,剩下的边全部在最短路图上,并且 \(dis(u)=dis(v)\)。我们先计算出在最短路图上从 \(s\) 出发到每个点的简单路径条数 \(dp_s[u]\),以及在最短路图上从 \(t\) 出发到每个点的简单路径条数 \(dp_t[u]\),然后枚举不在最短路图上且满足 \(dis(u)=dis(v)\) 的边 \((u,v)\),将\(dp_s[u]\times dp_t[v]+dp_s[v]\times dp_t[u]\) 累加到答案即可。
Code
#include <bits/stdc++.h>
using namespace std;
#define LL long long
template<typename elemType>
inline void Read(elemType& T) {
elemType X = 0, w = 0; char ch = 0;
while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
T = (w ? -X : X);
}
const int maxn = 200010;
const LL MOD = 1e9 + 7;
int T, n, m, s, t;
struct Graph {
struct edge { int Next, to, w; };
edge G[maxn << 1];
int head[maxn];
int cnt;
Graph() :cnt(2) {}
void clear(int n) {
cnt = 2;fill(head, head + n + 2, 0);
}
void add_edge(int u, int v) {
G[cnt].w = 0;
G[cnt].to = v;
G[cnt].Next = head[u];
head[u] = cnt++;
}
};
Graph G;
struct Node { int Value, ID; };
struct cmpA { bool operator()(Node A, Node B) { return A.Value > B.Value; } };
priority_queue<Node, vector<Node>, cmpA> Q;
int dis[maxn];
bool vis[maxn];
void Dijkstra(int st) {
for (int i = 1;i <= n;++i) {
dis[i] = 0x3f3f3f3f;
vis[i] = false;
}
dis[st] = 0;Q.push((Node) { 0, st });
while (!Q.empty()) {
int u = Q.top().ID;Q.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = G.head[u];i;i = G.G[i].Next) {
int v = G.G[i].to;
if (vis[v]) continue;
if (dis[v] > dis[u] + 1) {
dis[v] = dis[u] + 1;
Q.push((Node) { dis[v], v });
}
}
}
}
void build_spg() {
for (int u = 1;u <= n;++u) {
for (int i = G.head[u];i;i = G.G[i].Next) {
int v = G.G[i].to;
if (dis[u] + 1 == dis[v])
G.G[i].w = G.G[i ^ 1].w = 1;
}
}
}
LL dp_s[maxn], dp_t[maxn];
queue<int> Que;
void calc_dp(int st, LL* dp, int opt) {
for (int i = 1;i <= n;++i) {
vis[i] = false;
dp[i] = 0;
}
dp[st] = 1; vis[st] = true; Que.push(st);
while (!Que.empty()) {
int u = Que.front(); Que.pop();
for (int i = G.head[u];i;i = G.G[i].Next) {
if (G.G[i].w == 0) continue;
int v = G.G[i].to;
if (dis[v] * opt > dis[u] * opt) dp[v] = (dp[v] + dp[u]) % MOD;
if (!vis[v]) { vis[v] = true; Que.push(v); }
}
}
}
int main() {
Read(T);
while (T--) {
Read(n); Read(m); Read(s); Read(t);
G.clear(n);
for (int i = 1;i <= m;++i) {
int u, v;
Read(u); Read(v);
G.add_edge(u, v);
G.add_edge(v, u);
}
Dijkstra(s);
build_spg();
calc_dp(s, dp_s, 1);
calc_dp(t, dp_t, -1);
LL ans = 0;
for (int u = 1;u <= n;++u) {
for (int i = G.head[u];i;i = G.G[i].Next) {
if (G.G[i].w) continue;
int v = G.G[i].to;
if (dis[u] == dis[v]) {
ans = (ans + dp_s[u] * dp_t[v] % MOD + dp_s[v] * dp_t[u] % MOD) % MOD;
G.G[i].w = G.G[i ^ 1].w = 1;
}
}
}
ans = (ans + dp_s[t]) % MOD;
printf("%I64d\n", ans);
}
return 0;
}