CF1495D BFS Trees

感觉数据规模越小,越不确定算法的复杂度是什么,对可能的解法也一头雾水。

那就回到问题本身思考吧。

所谓的BFS树,顾名思义,可以由根出发BFS扩展形成。

f(x,y),y也可以视为树根,这意味着——

首先,x和y之间的距离本来就是最短距离,并且x和y的树路上的每个点到y的距离也必然是最短路径。

接下来就是,看,别的点到y的距离也是最短的,为什么。

这意味着d(a,y)=d(a,x)+d(y,x)

n很小,让我们可能对每个点都做一次bfs,O(NM)

从而求出d[][]

然后我们也可以O(N^2)枚举(x,y)配对,固定了x和y后,

假设一个环,靠近y的那个点z,反而是由x出发来连接的,也就是z x y

那么显然d(z,y)就不是树上的z和y的距离了。

 

假设,我们换个视角,x和y最终的生成树,可以理解为从x和y出发分别进行bfs,对方访问过的点不再被自己访问,但是如果分属两个连通块的话就连边合并。

这样也最终会形成一个树。而且,假设树上那些由x走出来的点称为A点,y走出的称为B点

显然A点与x的树上距离就是d(.,x),B点对y同理

那么A点与y呢?其实想象一下,树上只有一条边是连接A点和B点的。

因此,我们可以O(N^2M)来枚举点对以及一条边,看看点对之间是否存在过这条边的最短路。

我们可以求出所有的边,使得它划分A点和B点,并且——

 

暂时弃疗。

 

发现一个性质,对于以x和y为两根的树,原图中满足d(u,x)+d(u,y)==d(x,y)的点u一定要在树中x到y的路径上,不然,u从树上路径到x或y的距离中必然有一个不是最短距离。

反过来,树中x到y的路径上的所有点u都满足d(u,x)+d(u,y)==d(x,y)。

因此,如果x和y固定,对应的BFS树的x到y的路径上的点也是确定的。

剩下的点,我们考虑如何把点连到这个连通块上,从而生成树。

假设点u还未连通,当前树上有一个点v,如果我们想把u和v相连,需要满足什么条件?

连上后,u到x的距离要等于d(u,x),对y同理,而我们已经有v到x的树上距离=d(v,x)了

因此必然要满足d(u,x)=d(v,x)+1和d(u,y)=d(u,y)+1

对u,我们可以找出所有这样的点v中任何一点连边。

而注意到 这样的点是可以通过到x的距离或者到y的距离来分类的,每一个阶段处理一类的点。

因此每次点u的可取点v数量相乘就是ans。

 

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,n) for (int i=1;i<=n;i++)
#define REP(i,a,b) for (int i=a;i<=b;i++)
 
#define pb push_back
#define fi first
#define se second
#define pi pair<int,int>
#define mp make_pair
 
typedef long long ll;
typedef complex<double> comp;
 
const int inf=0x3f3f3f3f;
const ll linf=1e18;
const int N=700;
const double eps=1e-10;
const ll mo=998244353;

int n,m;
vector<int> g[N];
int e[N][2];
int d[N][N];
int f[N];
queue<int> q;
ll ans[N][N];
int main() {
 
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
 
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n>>m;
    FOR(i,m) {
        int x,y;
        cin>>x>>y;
        g[x].pb(y);
        g[y].pb(x);
        e[i][0]=x,e[i][1]=y;
    }
    memset(d,0x3f,sizeof(d));
    FOR(i,n) {
        while (!q.empty()) q.pop();
        q.push(i);
        d[i][i]=0;
        while (!q.empty()) {
            int t=q.front();
            q.pop();
            for (auto &u:g[t]) {
                if (d[i][u]>d[i][t]+1) {
                    d[i][u]=d[i][t]+1;
                    q.push(u);
                }
            }
        }
    }
    FOR(i,n) FOR(j,n) {
    	FOR(k,n) f[k]=0;
        int cnt=0;
        FOR(k,n) if (d[k][i]+d[k][j]==d[i][j]) cnt++;
        if (cnt>d[i][j]+1) continue;
        FOR(l,m) {
            int a=e[l][0],b=e[l][1];
            if (d[a][i]==d[b][i]+1&&d[a][j]==d[b][j]+1) ++f[a];
            swap(a,b);
            if (d[a][i]==d[b][i]+1&&d[a][j]==d[b][j]+1) ++f[a];
        }
        ll res=1;
        FOR(k,n) if (d[k][i]+d[k][j]!=d[i][j]) res=(res*f[k])%mo;
        ans[i][j]=res;
    }
   	FOR(i,n) {
   		FOR(j,n) cout<<ans[i][j]<<" ";
   		cout<<endl;
	}
    return 0;
}

  

posted @ 2021-03-11 20:10  AngelKnows  阅读(250)  评论(2)    收藏  举报