【CF1611】E. Escape The Maze(easy+hard)

这篇博客介绍了如何解决Codeforces上的两道竞赛题目E1和E2。问题涉及树形图中判断节点是否为安全点,即从这些节点出发能避免被朋友节点捕获。文章详细阐述了深度优先搜索(DFS)的运用,以及如何通过节点深度和最近朋友节点的深度比较来确定安全点。在E2问题中,进一步探讨了如何优化算法,减少朋友节点的影响以求得最优解。
摘要由CSDN通过智能技术生成

E1题目链接:https://codeforces.com/contest/1611/problem/E1
E2题目链接:https://codeforces.com/contest/1611/problem/E2

分析

我们定义一个点叫做安全点,即走到这个点上即可到达安全的叶子节点(不会被朋友逮到);朋友初始站的点叫朋友点,否则叫非朋友点; d e e p [ i ] deep[i] deep[i]表示第 i i i号点的深度, m d [ i ] md[i] md[i]表示在第 i i i号点下面距离 i i i最近的朋友点的深度。

很明显若一个点是叶子节点,同时它是非朋友点,那么它就是一个安全点;同样很明显若一个点是朋友点,那么它以及它下方的点一定不是安全点。我们可以将安全点的状态转移向它的父亲点进行转移。
如何确定一个非叶子非朋友节点 i i i是否是安全点呢?若 i i i的孩子节点中有安全点,同时
在第 i i i号点下面距离 i i i最近的朋友点的距离比该点到 1 1 1号点的距离大( d e e p [ i ] − 1 < m d [ i ] − d e e p [ i ] deep[i]-1<md[i]-deep[i] deep[i]1<md[i]deep[i]),也就是朋友抓不到Vlad,那么 i i i号点就是一个安全点。

对于E1,只要判断最终 1 1 1号点是不是安全点即可。
对于E2,如果 1 1 1号点不是安全点,那么想一下,我们如果将所有的朋友点都尽量往上移动,移到最极限的位置(即刚好和Vlad碰到),然后dfs搜索到朋友点就 a n s + 1 ans+1 ans+1,并且不必再遍历下去。我们可以利用 m d md md数组来实现这个过程,即搜索到一个点 i i i满足 d e e p [ i ] − 1 ≥ m d [ i ] − d e e p [ i ] deep[i] - 1 \geq md[i] - deep[i] deep[i]1md[i]deep[i],就 a n s + 1 ans+1 ans+1,并且不必再遍历下去。

具体看代码

代码

E1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define fi first
#define se second
#define lson (k << 1)
#define rson (k << 1 | 1)
 
const ll LINF = 1e18;
const int INF = 1e9 + 7;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const ll P = 1e9 + 7;
const double eps = 1e-7;
 
int n, k;
int f[N], safe[N], deep[N], md[N];
vector<int> g[N];
 
void dfs(int u, int fa)
{
    deep[u] = deep[fa] + 1;
    if(f[u])
    {
        md[u] = min(md[u], deep[u]);
        return;
    }
    if(g[u].size() == 1 && u != 1)
    {
        safe[u] = 1;
        return;
    }
    int ifsafe = 0, mn = INF;
    for(int i=0,v;i<g[u].size();i++)
    {
        v = g[u][i];
        if(v == fa) continue;
        dfs(v, u);
        md[u] = min(md[u], md[v]);
        if(safe[v]) ifsafe = 1;
    }
    if(ifsafe && deep[u] - 1 < md[u] - deep[u]) safe[u] = 1;
}
 
int main()
{
    int T = 1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<=n;i++) g[i].clear(), f[i] = deep[i] = safe[i] = 0, md[i] = INF;
        for(int i=1,x;i<=k;i++)
        {
            scanf("%d",&x);
            f[x] = 1;
        }
        for(int i=1,u,v;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1, 0);
        if(safe[1]) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

E2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define fi first
#define se second
#define lson (k << 1)
#define rson (k << 1 | 1)
 
const ll LINF = 1e18;
const int INF = 1e9 + 7;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const ll P = 1e9 + 7;
const double eps = 1e-7;
 
int n, k, ans;
int f[N], safe[N], deep[N], md[N];
vector<int> g[N];
 
void dfs(int u, int fa)
{
    deep[u] = deep[fa] + 1;
    if(f[u])
    {
        md[u] = min(md[u], deep[u]);
        return;
    }
    if(g[u].size() == 1 && u != 1)
    {
        safe[u] = 1;
        return;
    }
    int ifsafe = 0, mn = INF;
    for(int i=0,v;i<g[u].size();i++)
    {
        v = g[u][i];
        if(v == fa) continue;
        dfs(v, u);
        md[u] = min(md[u], md[v]);
        if(safe[v]) ifsafe = 1;
    }
    if(ifsafe && deep[u] - 1 < md[u] - deep[u]) safe[u] = 1;
}

void dfs2(int u, int fa)
{
    if(deep[u] - 1 >= md[u] - deep[u])
    {
        ans++;
        return;
    }
    for(int i=0,v;i<g[u].size();i++)
    {
        v = g[u][i];
        if(v == fa) continue;
        dfs2(v, u);
    }
}
 
int main()
{
    int T = 1;
    scanf("%d",&T);
    while(T--)
    {
        ans = 0;
        scanf("%d%d",&n,&k);
        for(int i=0;i<=n;i++) g[i].clear(), f[i] = deep[i] = safe[i] = 0, md[i] = INF;
        for(int i=1,x;i<=k;i++)
        {
            scanf("%d",&x);
            f[x] = 1;
        }
        for(int i=1,u,v;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1, 0);
        if(safe[1]) printf("-1\n");
        else
        {
            dfs2(1, 0);
            printf("%d\n",ans);
        }
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值