当前位置: 首页 > article >正文

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();
    }
}

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


http://www.kler.cn/a/527917.html

相关文章:

  • Python 列表(使用列表时避免索引错误)
  • Python练习(3)
  • 【Proteus仿真】【51单片机】多功能计算器系统设计
  • 合并2个排序的链表
  • [EAI-026] DeepSeek-VL2 技术报告解读
  • 代码随想录算法训练营第三十八天-动态规划-完全背包-139.单词拆分
  • 深度学习编译器的演进:从计算图到跨硬件部署的自动化之路
  • 《大数据时代“快刀”:Flink实时数据处理框架优势全解析》
  • 翻译: Dario Amodei 关于DeepSeek与出口管制一
  • (二)QT——按钮小程序
  • 本地运行大模型效果及配置展示
  • 牛客周赛 Round 77
  • Java 16进制 10进制 2进制数 相互的转换
  • 数据分析系列--⑦RapidMiner模型评价(基于泰坦尼克号案例含数据集)
  • 通过.yml文件创建环境
  • 反射、枚举以及lambda表达式
  • Ubuntu下的Doxygen+VScode实现C/C++接口文档自动生成
  • 想品客老师的第九天:原型和继承
  • Nginx代理
  • 面试回顾——1
  • JAVA实战开源项目:房屋租赁系统(Vue+SpringBoot) 附源码
  • Visual RAG: Expanding MLLM visual knowledge without fine-tuning 论文简介
  • 【文件整理】文件命名、存放、分类建议
  • JDK的动态代理:深入理解与实践
  • keil5如何添加.h 和.c文件,以及如何添加文件夹
  • 安装Maven(安装包+步骤)