题目大意
给定一棵树以及$m$条巴士路线,对于每条路线可以在起点和终点上车,在路线上任意点下车。求从节点$1$出发,到每个点所需乘坐的最少巴士数量,如果不能到达则输出$-1$。
树以如下方式给出:
第一行包括两个整数$n$和$m$,分别表示点的数量和巴士路线的数量。接下来一行共有$n-1$个数,第$i$个数$p[i]$表示$i+1$和$p[i]$连有一条边,且$p[i]<=i$。
解题思路
裸的$bfs$。把$m$条巴士路线看成$m$条边,从节点$1$开始$bfs$,遍历到的每个点都更新一下原图中它的所有父节点的答案。碰到已经被赋值过的父节点就停止。因为已经被赋值过表示在之前某条巴士路线就已经经过这个点,并且由于是从节点$1$进行$bfs$,所以从$1$到这一点的路径一定是走过的。
题中特殊的建树方式,可以看成是每个$i+1$的父节点即为$p[i]$。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <bits/stdc++.h> #define maxn 200100 #define int long long typedef __int128_t int128; using namespace std; const double eps=1e-8; int fa[maxn],ans[maxn]; vector<int>bus[maxn]; void solve(){ int n,m; cin >> n >> m; for(int i=2;i<=n;++i) ans[i]=1e9,cin >> fa[i]; for(int i=1;i<=m;++i){ int x,y; cin >> x >> y; bus[x].push_back(y); bus[y].push_back(x); } queue<int>q; q.push(1); ans[1]=0; while(q.size()){ int t=q.front(); q.pop(); for(auto u:bus[t]){ while(ans[u]==1e9){ ans[u]=ans[t]+1; if(!bus[u].empty()) q.push(u); u=fa[u]; } } } for(int i=2;i<=n;++i){ if(ans[i]!=1e9) cout << ans[i] << ' '; else cout << -1 << ' '; } cout << '\n'; } signed main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t=1; while(t--){ solve(); } return 0; }
|