CF1495D - BFS Trees(树)
题意
定义一个图的生成树是以节点 \(s\) 为根的 BFS 树,当且仅当对任意节点\(t\),图中 \(s\) 到 \(t\) 的最短路径长度等于树上 \(s\) 到 \(t\) 的最短路径长度。
对于一个图,定义 \(f(x, y)\) 为该图满足「同时是以节点 \(x\) 为根的 BFS 树和以节点 \(y\) 为根的 BFS 树」的生成树数量。
给出一个 \(n\) 个节点 \(m\) 条边的无向连通图,请对每对 \(i\), \(j\), 计算 \(f(i, j)\) 对 \(998244353\) 取模的值。
\(n\le 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 '\n'
#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] << " \n"[j == n];
}
}
}