返回顶部

D 与 S

题目链接:D 与 S

题目描述:

\(S\)在追杀\(D\)。 现在,\(D\) 在一张有\(N\)\(M\)边的无向图的\(1\)号点(顶点从\(1\)开始编号)。 每一秒\(S\)会剪掉与\(D\)相邻的一条边,然后\(D\)会走到一条没被剪掉的边的终点。有\(K\)个关键点,如果\(D\)到达了其中一个关键点,则\(D\)逃跑成功。\(S\)要尽可能地阻止\(D\)逃跑成功。 你需要回答:若都采用最优策略,\(D\)能不能逃跑成功。注意,如果\(D\)一开始就处在关键点,也算做他逃跑成功。

思路:根据题意可以看出,当一个点所连的点里面有不少于\(2\)关键点时,这个点也是关键点,所以我们可以使用类似拓扑排序的思想,将\(K\)个关键点加入队列,然后进行\(BFS\),如果一个点被访问了超过两次,说明它是关键点,将其也加入队列。最后只需要判断\(1\)号点是否是关键点即可。

时间复杂度:\(O(T\times M)\)

参考代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 5e5 + 5;

int T , n , u , v, m , k;
vector<vector<int>>graph(N);
queue<int> q;
int cnt[N], a, vis[N];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> T;
    while(T--){
        cin >> n >> m >> k;
        for(int i = 1 ; i <= k ; ++i){
            cin >> a;
            q.push(a);
            vis[a] = true;
        }
        for(int i = 1 ; i <= m ; ++i){
            cin >> u >> v;
            graph[u].push_back(v);
            graph[v].push_back(u);
        }
        while(!q.empty()){
            int ver = q.front(); q.pop();
            for(auto& v : graph[ver]){
                ++cnt[v];
                if(!vis[v] && cnt[v] >= 2) q.push(v),vis[v] = true;
            }
        }
        puts(vis[1] ? "yes" : "no");
        for(int i = 1 ; i <= n ; ++i) graph[i].clear();
        for(int i = 1 ; i <= n ; ++i) cnt[i] =0, vis[i] = false;
    }
    return 0;
}
posted @ 2021-12-12 18:58  cherish-lgb  阅读(52)  评论(0编辑  收藏  举报