题意:给定一个无向图 G(n, m),可以将其中任意一条边分裂成一条长度为任意的链(向边中插任意多个点),可以操作任意多次(也可以不操作)。问经过这样处理之后,从 1 号节点出发,至多走 k 步最多可以到多少个节点。
做法:将边分为bfs树边和非bfs树边,通过以下代码判断某个点的边是否是bfs树边,fa[x]为bfs途中的各点的父亲节点
for(auto i:mp[x]){
if(fa[i]==x||fa[x]==i)continue;
cnt++;
}
对于非bfs树边,可以任意分裂也即对于该点的两点都可以分裂,对于bfs树边,有且只有可能在该点是叶子节点的情况下分裂。遍历每个点,统计每个点的答案即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll n,m,k;
vector<ll>mp[100500];
ll vis[100500];
ll deep[100500];
ll fa[100500];
ll l,r;
ll deg[100500];
int main(){
// ios::sync_with_stdio(false);
// cin.tie(nullptr);
// cout.tie(nullptr);
cin>>n>>m>>k;
for(ll x=1;x<=m;x++){
cin>>l>>r;
mp[l].push_back(r);
mp[r].push_back(l);
}
queue<ll>t;
ll st=1;
t.push(st);
ll ans1=1,ans2=0;
fa[1]=-1;
for(ll x=1;x<=n;x++){
deep[x]=1145141919;
}
deep[1]=0;
while(!t.empty()){
ll u=t.front();
t.pop();
if(vis[u])continue;
vis[u]=1;
for(auto v:mp[u]){
if(deep[u]+1<deep[v]){
deep[v]=deep[u]+1;
fa[v]=u;
t.push(v);
deg[u]++;
}
}
}
for(ll x=2;x<=n;x++){
if(deep[x]>k){
continue;
}
ans1++;
ll cnt=0;
for(auto i:mp[x]){
if(fa[i]==x||fa[x]==i)continue;
cnt++;
}
if(!deg[x])cnt=max(cnt,(ll)1);
ans2+=cnt*(k-deep[x]);
}
//cout<<ans1<<" "<<ans2<<endl;
cout<<ans2+ans1<<endl;
return 0;
}