CF 1496.F BFS Tree---生成树+最短路

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.

cf题目

题目大意:
给定一张无向图,取任意两点进行如下操作:
以这两点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");
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值