陕西计算机学会SYAP2025年3月月赛-进阶组T2 猫树

小明的宠物猫账账躲在了树上,小明来捕捉它。

树一共有 nnn 个节点,账账在根节点 xxx 处。每一秒钟,小明可以封锁一个节点(不可以为账账在的节点),然后账账可以移动到一个树上相邻的未被封锁的节点。若账账逃到了叶子,那么它就逃脱成功。

小明发现这样很有可能让账账逃跑。于是决定提前封锁一些节点。他想知道,他最少需要提前封锁多少节点,才可以不让账账成功逃脱。

输入格式

本题有 TTT 组测试数据。对于每组数据:

第一行一个数 nnn

接下来 n−1n-1n1 行,每行 u,vu,vu,v 表示树上一条边。

最后一行一个数 xxx 表示猫在的节点。

输出格式

对于每组数据输出一行表示答案。

样例

样例输入

1
7
1 2
2 4
2 5
1 3
3 6
3 7
1

样例输出

1

提示说明

对于样例数据,提前封禁 222 号点,就可以保证账账无法逃脱。

对于 10%10\%10% 的数据,2≤n≤202 \le n \le 202n20

对于 40%40\%40% 的数据,2≤n≤50002 \le n \le 50002n5000

对于 100%100\%100% 的数据,2≤n≤2000002 \le n \le 2000002n2000001≤x≤n1\le x\le n1xn1≤T≤51\le T\le 51T5

解析

若某个子节点有两条可以逃跑的路线,就需要事先封堵一条。
对于叶子节点,可以直接逃脱。
递归计算每个节点可以逃跑的路线,对于多于一条的进行封堵,详见代码:

感谢 广州孩宝机器人的王淞老师 提供的修改意见

修改了原题解存在会输出-1的问题

#include<bits/stdc++.h>
using namespace std;
int t, n, x;
vector <int> g[200005];//邻接表存树
int dfs(int gf, int f) {
    //叶子节点,可以逃脱,定义为2条路
    if (g[f].size() == 1) return 2;
    int ret = 0; //初始化可逃跑路线为0
    for(int i = 0; i < g[f].size(); i++) { //递归每一个子节点
        int s = g[f][i]; //子节点
        if (s != gf) { //排除父节点
            int t = dfs(f, s); //递归子节点的逃跑路线
            if (t >= 2) { //如果子节点有两条以上可以逃跑的路线
                ret++;//该子节点可以逃掉
            }
        }
    }
    return ret;//返回可逃跑路线
}
int main() {
    cin >> t;
    while(t--) {
        cin >> n;
        for(int i = 1; i < n; i++) { //邻接表存树
            int u, v;
            cin >> u >> v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        cin >> x; //根
        cout << max(dfs(0, x) - 1, 0) << endl; //从根开始递归
        for(int i = 1; i <= n; i++) { //清空邻接表
            g[i].clear();
        }
    }
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长春高老师编程(信奥工作室)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值