K. Birdwatching(2019-2020 ICPC Southwestern European Regional Programming Contest (SWERC 2019-20))
题意:
有N个顶点,M条边,中心点K,给你M条有向边信息,问你在这个图中满足条件的点有几个并输出他们。
如果点A满足条件,则:
1.A一定与K相连,并且一定有一条边为A->K
2.从A走到K的所有路径中,一定包含A->K这条边
思路:
首先:
对于所有满足条件的点A,都有A->K,又要求所有A到K的所有路径一定经过A->K , 这就意味着:
A有且仅有一条通往K点的路,也就是A->K点这条的路
也就是说:如果一个点,它可以通过两种不同的路径到达K点,那么他就不符合条件。
做法是:
建立反向图,遍历K可以一步访问到的点,从这些点开始进行BFS/DFS
比如,K可以走到A,那么我从A(此时的A是源点)开始搜索,A可以走到B,由于这是反向图,那么反过来,B肯定可以走到A然后再走到K
那么我只要判断,这个点B是否可以由两个不同的源点走到,如果可以,那么不符合条件,如果可以,输出
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6 + 10; #define ll long long #define ios std::ios::sync_with_stdio(false) const double ep = 1e-6; vector<int>G[maxn]; int ans[maxn]; int n , m , k; int prei[maxn]; void dfs(int s , int pre) { ans[pre] ++; prei[pre] = s; for(int i = 0 ; i < G[pre].size() ; i ++){ int now = G[pre][i]; if(ans[now] >= 2 ||now == k || now == s || prei[now] == s) continue; dfs(s , G[pre][i]); } } vector<int>vec; signed main() { ios;cin.tie(0); cin >> n >> m >> k; for(int i = 1 ; i <= m ; i ++){ int u , v; cin >> u >> v; G[v].push_back(u); } for(int i = 0 ; i < G[k].size() ; i ++){ dfs(G[k][i] , G[k][i]); } for(int i = 0 ; i < G[k].size() ; i ++){ if(ans[G[k][i]] < 2){ vec.push_back(G[k][i]); } } cout << vec.size() << '\n'; for(int i = 0 ; i < vec.size() ; i ++) cout << vec[i] << '\n'; return 0; }