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;
}
View Code

 

 

 

 

 

posted @ 2020-09-22 22:49  GoodVv  阅读(316)  评论(0编辑  收藏  举报