DFS-树的重心

在了解这道题目之前,我们首先需要知道图的深搜是如何进行的,我们用一个无联通单向图来记录这一类,因为单向图再添加的时候只需要往两个节点分别都添加连接即可,而树是图的一种特例。

图的深度优先搜索模板

思路

我们使用队列来存储图中的节点以及所有的线。我们使用e数组来存储节点中的值,ne数组来存储这个节点所连接的其他节点(顺序无所谓),h数组用来存储所有的头节点,每个头节点都有自己的队列,idx表示队列中点的个数,跟模拟队列实现一样。

代码

#include<iostream>

using namespace std;

const int N = 100010,M=N*2;
int h[N],e[M],ne[M],idx;
bool state[N];

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u){
    st[u] = true;
    
    for(int i=h[u];i!=-1;i=ne[i]){
        int j = e[i];
        if(!st[j]) dfs(j);
    }
}

int main(void){
    memset(h,-1,sizeof h);
    
    return 0;
}

tips

开数组的时候要记得开二倍

题目示例

题面

样例

分析,思路

我们的目的是要得到最小的最大联通块,那么我们不妨可以遍历搜索每一个节点,然后分别得出每一个点删除后所得到的最大连通块,再将它们进行比较,最后选出最小值即可。那么我们现在的问题就是如何得到每个节点的最大连通块,分析可知我们删除一个节点后,会剩余两大类:其所有的子节点为一类,删除该节点的父节点为一类。我们只需要比较这些当中哪个最大即可

代码

#include<iostream>
#include<cstring>

using namespace std;

const int N = 100010,M=N*2;
int n;
int idx,e[M],ne[M],h[M];
bool state[N];

int ans = N; //记录最终答案 

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int dfs(int u){
    state[u] = true; //标记一下搜索过了
    
    int sum=1,res=0; //sum存储的当前u树的大小,res存储的每一个连通块的最大值
    //遍历u的子树的所有子节点为根的子树(连通图)
    for(int i=h[u];i!=-1;i=ne[i]){
        int j = e[i];
        if(!state[j]){
            int s = dfs(j); //当前子树大小
            res = max(res,s); //解决“子树是最大的”这种情况
            sum+=s; //sum循环完就是所有子节点加上它自身的和
        }
    }
    res = max(res,n-sum); //n-sum是去除该节点后父树的大小(节点多少)
    
    ans = min(ans,res);
    
    return sum;
}

int main(void){
    cin >> n;
    memset(h,-1,sizeof h);
    
    for(int i=0;i<n-1;i++){
        int a,b;
        cin >> a >> b;
        add(a,b);
        add(b,a);
    }
    
    dfs(1);
    
    cout << ans << endl;
    
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值