首页 > 其他分享 >CodeForces Round 898 (div 4) H题解析

CodeForces Round 898 (div 4) H题解析

时间:2024-07-17 12:52:23浏览次数:7  
标签:环上 898 拓扑 CodeForces KeyPoint div Valeriu

 

CodeForces Round 898 (div 4)
H. Mad  City

                                                    

大致思路     

  • 对于有n条边和n个点,说明这个图里面只有一个环
  • 并且两人同时开始和结束移动,所以可以得到当Valeriu进入到这个图里面的唯一的环里面时,Marcel就无法再抓到他,我们可以把离Valeriu最近的入环点叫做KeyPoint,所以我们就需要考虑Valeriu是否能在Marcel赶到KeyPoint之前赶到KeyPoint。
  • 所以找到入环点是这道题的切入点,找到入环点,我们就可以通过dfs暴搜来得出他们和入环点的距离来,通过比较来得出是否能够逃离。

Key:切入点的寻找

思路来源于洛谷的_Ink大佬

方法是通过拓扑,因为在拓扑的过程中,会一步步去删点删边,最后只剩下一个环。因为是要找离逃离者最近的入环点,所以我们可以把一开始的KeyPoint设为b点,即要逃离者所在地点,当 Keypoint 所在的点将被删时,由拓扑排序的特性,此时仅有一条边与其相连,所以我们可以在删这个点时顺势把KeyPoint 值更新到与被删点相连的那个点上。

由于拓扑排序不会删掉环上的点,所以当 KeyPoint 值不停更新,直到更新到环上的点时就不再发生变化。此时,KeyPoint 值就是我们想要的那个点的编号了。

这道题的图为无向图,所以拓扑过程中的删点删边条件应该为入度为1,这样环上的点就永远不会被删除。

完整代码

#include <bits/stdc++.h>
using namespace std;
const int N = 200060, M = N << 1;
int h[N], ne[M], e[M], idx;
int n, a, b, keypoint;
int to[N];//记录一个点的入度
bool vist[N], st[N];
int dista, distb;//记录a,b离关键点的距离
void add(int a, int b)//链式前向星式建图
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}
void topsort(int dot)//对入度为1的点进行拓扑
{
    vist[dot] = true;//把这个点标记,表示在此次拓扑中已经被访问
    for (int i = h[dot]; i!=-1; i = ne[i])
    {
        int j = e[i];
        if (vist[j] || to[j]==0)continue;//如果这个点已经被访问过,就跳过
        //如果这个点已经被删除也跳过
        to[dot]--;
        to[j]--;//因为是双向的道路,删边需要两个点的入度都减1
        if (dot == keypoint)keypoint = j;//删点,如果这个点是关键点就转移关键点
        if (to[j] == 1)topsort(j);//对于入度为1的点进行拓扑
    }
    vist[dot] = false;//恢复状态
}
void dfs(int x, int dist)//dfs暴搜求a和b到关键点的距离
{
    st[x] = true;//标记点已经访问
    if (x == a)dista = min(dista, dist);
    if (x == b)distb = min(distb, dist);
    for (int i = h[x]; ~i; i = ne[i])
    {
        int j = e[i];
        if (st[j])continue;//如果点已经被访问就跳过
        dfs(j, dist + 1);
    }
    st[x] = false;//恢复现场
}
void init()//对于每一次的状态的初始化
{
    memset(h, -1, sizeof h);
    idx = 0;
    memset(to, 0, sizeof to);
    memset(st, 0, sizeof st);
    memset(vist, 0, sizeof vist);
    dista = distb = 0x3f3f3f3f;
}
void solve()
{
    cin >> n >> a >> b;
    init();
    keypoint = b;
    for(int i=1;i<=n;i++)
    {
        int u, v;
        cin >> u >> v;
        add(u, v);
        add(v, u);
        to[u]++;
        to[v]++;//因为是双向道路,所以两个点的入度都+1
    }
    for (int i = 1; i <= n; i++)if (to[i] == 1)topsort(i);
    //找到入度为1的点进行拓扑
    if (to[b] >= 2 && a != b)//如果一开始b就在环上,而且a没有和b在同一栋大楼,就说明可以无期限逃
    {
        cout << "YES" << endl;
        return;
    }
    else if (a == b) {//如果a和b在同一栋大楼,就直接被抓了
        cout << "NO" << endl;
        return;
    }
    dfs(keypoint, 0);//DFS查找a和b两点离关键点的距离
    
    //如果a到关键点的距离大于b到关键点的距离,说明b可以比a先到环上,所以可以无期限逃,反之不可以
    if (dista > distb)cout << "YES" << endl;
    else cout << "NO" << endl;
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

   

 

 

                         

标签:环上,898,拓扑,CodeForces,KeyPoint,div,Valeriu
From: https://www.cnblogs.com/era768/p/18307059

相关文章

  • Codeforces Round 958 (Div. 2)
    题目链接:CodeforcesRound958(Div.2)总结:C因为常数没转\(longlong\)\(wa\)两发,难绷。A.SplittheMultisetfag:模拟Description:给定一个\(n\)和一个\(k\),每次可以将\(n\)减掉一个数\(u\),然后插入\(x\)个数,\(x<=k\),并且插入的数之和等于\(u\)。求将其转化为全\(1\)的最......
  • Codeforces Round 957 (Div. 3)
    知识点1.几个数相乘时,更小的数增加会比更大的数增加得到的乘积来得大题解A.OnlyPluses1.几个数相乘时,当更小的数增大时,得到的乘积会比更大的数增大来得大,也就是更小的数字权重会比较大,那么在5次+1的过程中,每次找最小值++即可#include<bits/stdc++.h>#defineintlonglon......
  • Codeforces Round 898 (Div. 4)(A~H)
    目录A.ShortSortB.GoodKidC.TargetPracticeD.1DEraserE.BuildinganAquariumF.MoneyTreesG.ABBCorBACBH.MadCityA.ShortSortProblem-A-Codeforces暴力枚举每个位置的交换即可。#include<iostream>#include<algorithm>#include<queue......
  • CF1898D Absolute Beauty 题解
    思路容易发现,如果\(a_i>b_i\)则将\(a_i\)和\(b_i\)交换。在数轴上标出要交换的四个数的位置若线段\(a_ib_i\)和线段\(a_jb_j\)互不相交,此时交换比两条线段处于其他位置时更优。具体证明这里就不再赘述,其他题解讲的已经很清楚了。所以只需交换最大的\(a_i\)和最小......
  • Codeforces Round 957 (Div. 3)
    题目链接:CodeforcesRound957(Div.3)总结:E不懂,F差一个set去重A.OnlyPlusesfag:枚举B.AngryMonkfag:模拟Solution:分裂的花费为\(a_i-1\),添加的花费为\(a_i\)。C.GorillaandPermutationfag:思维Solution:大于等于\(k\)的数,逆序放在最前面,小于等于\(m\)的数,从最后面......
  • Codeforces Round 958 (Div. 2)补题
    文章目录A题(拆分多集)B题(获得多数票)C题(固定OR的递增序列)A题(拆分多集) 本题在赛时卡的时间比较久,把这题想复杂了,导致WA了两次。后来看明白之后就是将n每次转换成k-1个1,到最后分不出来k-1个1直接一次就能分完,即结果加一;#include<bits/stdc++.h>#definein......
  • CodeForces 1983A Array Divisibility
    题目链接:CodeForces1983A【ArrayDivisibility】思路    按规律可得,当a[i]=i时满足题目要求。代码#include<functional>#include<iostream>#include<algorithm>#include<queue>#include<stdio.h>#include<string>#include<cstring......
  • CodeForces 1983B Corner Twist
    题目链接:CodeForces1983B【CornerTwist】思路    可以发现操作一次,被操作位置的对应每一横行和每一纵行的加减数都是3,所以可以根据网格a和b的横纵状态确定是否通过操作使得网格a到达网格b。代码#include<bits/stdc++.h>usingnamespacestd;#definelllonglo......
  • CodeForces 1992A Only Pluses
    题目链接:CodeForces1992A【OnlyPluses】思路    代码#include<functional>#include<iostream>#include<algorithm>#include<queue>usingnamespacestd;#definelllonglongconstintN=500+10;inta[N];voidsolve(){intn......
  • CodeForces 1992D Test of Love
    题目链接:CodeForces1992D【TestofLove】思路    从起点开始起跳,找出下一个木头的位置,若与当前位置的距离小于等于m,则可以直接跳过去,否则判断当前位置与下一个木头之间有没有鳄鱼,有鳄鱼则不能到达对岸,否则继续查找下一个木头,直到对岸。代码#include<functional>......