题意
定义一个图的生成树是以节点 (s) 为根的 BFS 树,当且仅当对任意节点(t),图中 (s) 到 (t) 的最短路径长度等于树上 (s) 到 (t) 的最短路径长度。
对于一个图,定义 (f(x, y)) 为该图满足「同时是以节点 (x) 为根的 BFS 树和以节点 (y) 为根的 BFS 树」的生成树数量。
给出一个 (n) 个节点 (m) 条边的无向连通图,请对每对 (i), (j), 计算 (f(i, j)) 对 (998244353) 取模的值。
(nle 400, m le 600)
题解
(n)和(m)都很小,故分别计算每个(f(x,y))。
设(dis(x,y))代表(x)到(y)的最短路上的长度(结点数),这个用bfs即可得到,(O(n^2m))。
对于每个(x,y),如果(x)到(y)的最短路多于1条,显然有(f(x,y)=0)。即对于结点(z),如果(dis(x,z)+dis(z,y)-1=dis(x,y)),那么(z)必定在(x)到(y)的最短路上,这样的(z)数量恰好为(dis(x,y))。
对于不在最短路上的结点,与它相邻的结点都是bfs树上潜在的父亲。设结点(i),与其相邻的结点为(j),如果有
[dis(i,x)=dis(j,x)+1 \
dis(i,y)=dis(j,y)+1
]
那么(j)在bfs树中就可以成为(i)的父亲。同样在bfs树中如果(j)要成为(i)的父亲,必须满足上面的条件。
如果为每个结点都任选一个父亲,那么它们恰好能够构成一颗bfs树。故总共可能的bfs树就是每个结点(除了(x)到(y)路径上的结点)的父亲数的乘积。
总时间复杂度(O(n^2m))
#include <bits/stdc++.h>
#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 1e3 + 10;
const int M = 998244353;
const double eps = 1e-5;
vector<int> np[N];
int dis[N][N];
int cnt[N];
bool flag[N];
int ans[N][N];
void clear(int n) {
for(int i = 1; i <= n; i++) {
cnt[i] = 0;
flag[i] = 0;
}
}
int main() {
IOS;
int n, m;
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
np[u].push_back(v);
np[v].push_back(u);
}
for(int i = 1; i <= n; i++) {
queue<int> q;
q.push(i);
dis[i][i] = 1;
while(!q.empty()) {
int cur = q.front();
q.pop();
for(int nt : np[cur]) {
if(dis[i][nt]) continue;
dis[i][nt] = dis[i][cur] + 1;
q.push(nt);
}
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
int num = 0;
clear(n);
for(int k = 1; k <= n; k++) {
if(dis[i][k] + dis[k][j] - 1 == dis[i][j]) {
num++;
flag[k] = 1;
}
for(int nt : np[k]) {
if(dis[nt][i] == dis[k][i] + 1 && dis[nt][j] == dis[k][j] + 1)
cnt[nt]++;
}
}
if(num != dis[i][j]) continue;
ll res = 1;
for(int k = 1; k <= n; k++) {
if(flag[k]) continue;
res = res * cnt[k] % M;
}
ans[i][j] = res;
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
cout << ans[i][j] << "
"[j == n];
}
}
}