在了解这道题目之前,我们首先需要知道图的深搜是如何进行的,我们用一个无联通单向图来记录这一类,因为单向图再添加的时候只需要往两个节点分别都添加连接即可,而树是图的一种特例。
图的深度优先搜索模板
思路
我们使用队列来存储图中的节点以及所有的线。我们使用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;
}