题目链接:https://codeforces.com/contest/1496/problem/F
官方题解:https://codeforces.com/blog/entry/88533
题解提炼
记 (dist(x,y)) 为从点 (x) 到点 (y) 所经过的点的个数。
有两点性质:
- 对于点 (z),当 (dist(x,z)+dist(y,z)-1=dist(x,y)),那么点 (z) 应当是在从 (x) 到 (y) 的最短路上。
特别的,当这样的点的个树超过 (dist(x,y)) 个时,那么 (x) 和 (y) 作为根节点的BFS树同构必定不存在,举个例子,注意点 (1) 和点 (3):
5 6
1 2
2 3
1 4
4 3
1 5
3 5
- 对于其他不在从 (x) 到 (y) 的最短路的点 (u),要存在相邻的点 (v),使得 (dist(x,v)=dist(x,u)-1) 并且 (dist(y,v)=dist(y,u)-1)。
这一部分证明过程比较复杂请看官方题解。
AC代码
#include <bits/stdc++.h>
typedef long long ll;
#define llinf 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define SZ(x) (int)x.size()
#define mp make_pair
#define pii pair<int, int>
#define vi vector<int>
#define pb push_back
using namespace std;
const int MAXN = 400 + 10;
const int MAXM = 600 + 10;
const int mod = 998244353;
struct Edge {
int to, nex;
} e[MAXM << 1];
int head[MAXN], tol;
void addEdge(int u, int v) {
e[tol].to = v, e[tol].nex = head[u], head[u] = tol, tol++;
}
int dis[MAXN][MAXN];
void bfs(int s) {
queue<int> q;
dis[s][s] = 1;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; ~i; i = e[i].nex) {
int v = e[i].to;
if (!dis[s][v]) {
dis[s][v] = dis[s][u] + 1;
q.push(v);
}
}
}
}
ll res[MAXN][MAXN];
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) head[i] = -1;
while (m--) {
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v), addEdge(v, u);
}
for (int i = 1; i <= n; i++) bfs(i);
for (int x = 1; x <= n; x++) {
for (int y = x; y <= n; y++) {
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (dis[x][i] + dis[y][i] - 1 == dis[x][y]) cnt++; // i int the path of x to y
}
ll ans = 1;
if (cnt > dis[x][y]) ans = 0;
for (int u = 1; u <= n; u++) {
if (dis[x][u] + dis[y][u] - 1 != dis[x][y]) {
int fg = 0;
for (int i = head[u]; ~i; i = e[i].nex) {
int v = e[i].to;
if (dis[x][v] == dis[x][u] - 1 && dis[y][v] == dis[y][u] - 1) fg++;
}
ans = ans * fg % mod;
if (!ans) break;
}
}
res[x][y] = res[y][x] = ans;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
printf("%d ", res[i][j]);
}
printf("
");
}
}