Codeforces Round #706 (Div. 2) F. BFS Trees

传送门

题目大意

机翻的效果还不错,这里直接把有道的机翻搞过来了。
我们定义一个图的生成树是一个以顶点s为根的BFS树,当且仅当对于每个节点t,图中s和t之间的最短距离等于生成树中s和t之间的最短距离。
给定一个图,我们定义f(x,y)为该图中同时根为x和y的BFS树的生成树的数目。
给定一个有n个顶点和m条边的无向连通图。对所有i j,计算f(i,j),并对998244353取模

题解

我们先对每个点跑一遍最短路,得到数组dis[i][j],以i为根到j的距离,接下来i,j,k三层循环,外层两个循环代表以i为根和以j为根,然后k遍历所有点,如果dis[i][k]+dis[j][k]-1==dis[i][j],那么证明这个点在i到j之间,这些点的数量不能超过dis[j][i]的数量,否则就证明i和j之间有环,这样就不能建一个满足条件的树,接下来如果dis[x][i]+dis[y][i]-1>dis[x][y]我们只用找这个点的父亲满足dis[y][fa]==dis[y][i]-1&&dis[x][fa]==dis[x][i]-1,那么此时这个点就可以挂在这个父亲下面,我们只要找出有几个这样的父亲就好了,就是这个点所有可能存在的地方,所有点可能的情况乘起来就是答案了

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int MAX=405;
const int MOD=998244353;
vector<long long > v[MAX];
queue<long long > q;
long long dis[MAX][MAX];//x和y之间的点的数量 
long long print[MAX][MAX];
int main(){
	long long n,m,from,to;
	scanf("%lld%lld",&n,&m);
	while(m--){
		scanf("%lld%lld",&from,&to);
		v[from].push_back(to);
		v[to].push_back(from);
	}
	for(int i=1;i<=n;i++){
		q.push(i);
		dis[i][i]=1;
		while(!q.empty()){
			from=q.front();
			q.pop();
			for(int j=0;j<v[from].size();j++){
				if(!dis[i][v[from][j]]){
					q.push(v[from][j]);
					dis[i][v[from][j]]=dis[i][from]+1;
				}
			}
		}
	}
	for(int x=1;x<=n;x++){
		for(int y=x;y<=n;y++){
			long long ans=1,numdis=0;
			for(int i=1;i<=n;i++){
				if(dis[y][i]+dis[x][i]-1==dis[x][y]){
					numdis++;
				}
			}
			if(numdis>dis[x][y]){
				ans=0;
			}
			for(int i=1;i<=n;i++){
				if(dis[y][i]+dis[x][i]-1>dis[x][y]){
					numdis=0;
					for(int j=0;j<v[i].size();j++){
						if(dis[y][v[i][j]]==dis[y][i]-1&&dis[x][v[i][j]]==dis[x][i]-1){
							numdis++;
						}
					}
					ans=ans*numdis%MOD;
					if(!ans){
						break;
					}
				}
			}
			print[x][y]=print[y][x]=ans;
		}
	}
	for(int i=1;i<=n;i++){
		printf("%lld",print[i][1]);
		for(int j=2;j<=n;j++){
			printf(" %lld",print[i][j]);
		}
		printf("\n");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值