We define a spanning tree of a graph to be a BFS tree rooted at vertex s if and only if for every node t the shortest distance between s and t in the graph is equal to the shortest distance between s and t in the spanning tree.
Given a graph, we define f(x,y) to be the number of spanning trees of that graph that are BFS trees rooted at vertices x and y at the same time.
You are given an undirected connected graph with n vertices and m edges. Calculate f(i,j) for all i, j by modulo 998244353.
Input
The first line contains two integers n, m (1≤n≤400, 0≤m≤600) — the number of vertices and the number of edges in the graph.
The i-th of the next m lines contains two integers ai, bi (1≤ai,bi≤n, ai<bi), representing an edge connecting ai and bi.
It is guaranteed that all edges are distinct and the graph is connected.
Output
Print n lines, each consisting of n integers.
The integer printed in the row i and the column j should be f(i,j)mod998244353.
题目大意:
给定一张无向图,取任意两点进行如下操作:
以这两点x,y为源构造生成树,使得对于任意点k,有
dis[x][k]=min(dis[x][k])&&dis[y][k]=min(dis[y][k])即x,y点与k点的距离即为x,y与k的最短路径(之一),对于每一对x,y求能构造的生成树有多少(模998244353)
题目解析:
1.先将生成树等同于以x为源的生成树,对于每个y点,首先判断是否满足题目条件:
对于所有x,y之间的所有路径(指能从x出发且中途不经过x的情况下到达y)上的所有点k,需要满足:
对于dis[x][k]+dis[y][k]=dis[x][y]有且仅有一个dis[x][k](dis[y][k]
若不满足此条件,则路径上一定存在环,在构成生成树时,无法保证最小路
当路径上不存在环时,代表从x到y的最小路只有一条(不包括分叉路径)
2.对于生成树的分叉路径,上的所有点k,即:
dis[x][k]+dis[y][k]>dis[x][y]
当x和y有超过1个通向k的最短路时,即:
对于k的所有直接邻接点v,有x,y->v1->k&&x,y->v2->k即dis[x][v1]==dis[y][v1]&&dis[x][v2]==dis[y][v2]
此时每增加一条路径,生成树的种类就+1
将所有k的生成树种类相乘,就得到了ans[x][y]
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
#include<vector>
#define me(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
const int N = 677, inf = 700, mod = 998244353;
int n, m, dis[N][N], head[N], cnt = 1;
ll ans[N][N];
struct edge {
int to, nxt;
}e[N*N];
void add(int f, int t) {
e[++cnt].to = t; e[cnt].nxt = head[f]; head[f] = cnt;
}
void init_() {
me(dis, 1);
for (int i = 1; i <= n; i++)
dis[i][i] = 0;
}
void floyd() {
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
for (int i = 1; i <= n; i++)
if (dis[i][j] > dis[i][k] + dis[k][j])dis[i][j] =dis[j][i]= dis[i][k] + dis[k][j];
}
void check() {
for(int i=1;i<=n;i++)
for (int j = i; j <= n; j++) {
bool che = false;
vector<int>pos(inf*2, -1);
for (int k = 1; k <= n; k++)
if (dis[i][j] == dis[i][k] + dis[k][j]) {
if (pos[dis[i][k]] != -1) {che = true; break;}
pos[dis[i][k]] = k;
}
if (che)continue;
ll cnt1 = 1;
for (int k = 1; k <= n; k++)
if (dis[i][j] < dis[i][k] + dis[j][k]) {
ll cnt2 = 0;
for (int l = head[k], t; l; l = e[l].nxt) {
t = e[l].to;
if (dis[i][t] + 1 == dis[i][k] && dis[j][t] + 1 == dis[j][k])cnt2++;
}
cnt1 = cnt1 * cnt2 % mod;
}
ans[i][j] = ans[j][i] = cnt1;
}
}
int main() {
cin >> n >> m;
init_();
int f, t;
for (int i = 1; i <= m; i++) {
cin >> f >> t;
dis[f][t] = dis[t][f] = min(dis[f][t], 1);
add(f, t); add(t, f);
}
floyd();
check();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)printf("%d ", ans[i][j]);
printf("\n");
}
}