cf1695D1. Tree Queries (Easy Version)(div2)【树上问题】

13 篇文章 2 订阅
6 篇文章 0 订阅

传送门

题意

给定一棵树,并在树上任选一个节点 x x x (未知),每次都可以询问树上另一指定结点 v v v x x x 的最短路径,问最少需要几次询问,使得不论 x x x 是哪一个结点,都可以在询问次数及之内确认该点。

脑模可以发现,如果树的形状是一条链,可以仅通过询问一次叶子结点确认。不属于该结构的第一个例子是拥有 4 4 4 个结点的菊花图,假设以结点 2 2 2 为菊花中心,则确认其他三个结点中的任意一个都需要经历: 1. 1. 1.确定该点不是菊花中心 2. 2. 2.确定该点 两次询问。

此时若以 2 2 2 为根,则结点 1 , 3 , 4 1,3,4 1,3,4 均构成单独的链,可以发现增长 ( 如添加 ( 4 , 5 ) (4,5) (4,5) )其中的某条链不影响答案贡献。若在该基础上再增加 ( 4 , 6 ) (4,6) (4,6) ,由于子链的个数将增多,以 2 2 2 为根的答案为 3 3 3,但改变作为根的结点时,将影响树中的子链个数从而影响答案,使最优答案仍为 2 2 2

因此将所有点作为根的情况都跑一遍 d f s dfs dfs l i n k link link 为当前结点直接相连的子链个数,由此向上传递答案贡献值。

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;

const int N=2e5+10;
vector<int> g[N];

int dfs(int u,int fa){
    int cnt=0,link=0;
    for(auto v:g[u]) {
        if(v==fa) 
            continue;
        int x=dfs(v,u) ;
        if(!x)
            link++;
        cnt+=x;
    }
    cnt+=max((long long)0,link-1);
    // cout<<u<<" "<<cnt<<" "<<link<<endl;
    return cnt;
}

void solve() {
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) 
        g[i].clear();
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v) ;
        g[v].push_back(u) ;
    }
    int ans=n-1;
    for(int i=1;i<=n;i++){
        ans=min(ans,dfs(i,0)+1);
    }
    cout<<ans<< endl;
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值