Bootstrap

H. Mad City

题目链接:Problem - H - Codeforces

题目大意:给定一个带环的图, 以及a, b两点 判断再图上不断的移动, b想不与a相遇, a想捉到b, 并且二者只能移动一步。 若b跑不掉 NO 否则YES.

具体题目看链接

输入:

第一行包含一个整数 t (1≤t≤1000 ) - 测试用例数。

每个测试用例的第一行包含三个空格分隔的整数 n , a , b ( 3≤n≤2⋅1e5 ;( 3≤n≤2⋅1e5 ; 1≤a,b≤n )--

下面的 n 行分别包含两个整数 ui , vi .( 1≤ui,vi≤n, ui≠vi )-- ui 和 vi 之间有一条道路。

所有测试用例中 n 的总和不超过 2⋅1e5 。

保证有环.

解题思路: 通过题目信息, 判断两个点是否肯定会相遇

1.若两个点在环上,那么一定不会相遇,可直接输出YES.

2.该题考察基环树, 当b不在环上时,那么若a点还想与b点相遇, 只有在b点未进入环时堵住b进入环的入环点。所以判断b点到进入环的入点的距离 与 入环点到a点的距离,设入环点为p点。 则需判断  pa <= pb 是NO, 否则 YES.

3.做法, 由于基环树, 要用到拓朴排序, 去掉枝丫, 先判断b点是否在环里。 若不在,则需要做dfs, 搜索出pa, pb的距离。 而p点的求法, 在拓朴排序是删掉该点p时就更新p点的下一个点为p.机p == u 时, p = v.即可找出在环上离b点最近的点p.

#include<bits/stdc++.h>
using namespace std;

using i64 = long long;
using i128 = __int128;

void solve(){
    int n, a, b;
    cin >> n >> a >> b;
    vector<int> d(n+1);
    vector<vector<int>> g(n+1);
    for(int i=0; i<n; i++) {
        int u, v;
        cin >> u >> v;
        d[u]++, d[v]++;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    if(a==b){//特判
        cout << "NO\n";
        return;
    }
    queue<int> q;
    int p = b;

    for(int i=1; i<=n; i++) {
        if(d[i]==1) {
            q.push(i);
        }
    }
    //拓朴排序找里b点最近的环上点
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        d[u]--;
        for(int v : g[u]) {
            if(d[v]==0)continue;
            d[v]--;
            if(d[v]==1) {
                q.push(v);
            }
            if(u==p) {//删点时不断靠近环
                p = v;
            }
        }
    }

    set<int> st;
    for(int i=1; i<=n; i++) {
        if(d[i] >= 2) {
            st.insert(i);
        }
    }
    //判断b是否再环上
    if(st.contains(b)) {
        cout << "YES\n";
        return;
    }
    
    int dis1 = INT_MAX/2, dis2 = INT_MAX/2;
    vector<int> vis(n+1,0);
    //dfs搜索距离
    auto dfs = [&](auto&&dfs, int u,int len)->void{
        if(u==a || u==b){
            if(u==a) {
                dis1 = min(len, dis1);
            }
            if(u==b) {
                dis2 = min(len, dis2);
            }
            return;
        }
        vis[u] = 1; 
        for(int v : g[u]) {
            if(vis[v]==0) {
                dfs(dfs, v, len+1);
            }
        }
        vis[u] = 0;//再图上搜索,记得回溯
    };
    
    dfs(dfs, p, 0);
    if(dis1 <= dis2) {//最后的判断
        cout << "NO\n";
    }else{
        cout << "YES\n";
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while(t--) {
        solve();
    }
}

 欢迎各位点赞与观看, 欢迎大佬指正。

;