#include<iostream>
using namespace std;
int N = 1e5 + 10,M = N*2;
//h表示链表头,e存储的是所有的边,ne表示所有的next指针是多少,相当与n个单链表
int h[N],e[M],ne[M],idx;
//深度优先搜索和宽度优先搜索每个点只会遍历一次
bool st[N];//存一下那些点已经被遍历过了,就不要再遍历他了
void add(int a,int b){//a前插入b
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
//树和图的深度优先搜索的代码 时间复杂度是O(n + m),因为点数和边数呈线性关系
//u表示已经遍历到这个节点了
int dfs(int u){
st[u] = true;//首先先标记下当前这个点已经被搜索过了
//遍历下u的所有的初边
for(int i = h[u];i != -1;i = ne[i]){
// 存储当前结点对应图里边结点的编号是多少
int j = e[i];
//如果当前点没有做过的话,就一直搜,一条路走到黑
if(!st[j]) dfs(j);
}
}
int main(){
//头结点指向-1,n给单链表的头结点指向-1
memset(h,-1,sizeof h);
dfs(1);//从第一个点开始搜索
}
例题:
846. 树的重心
给定一颗树,树中包含n个结点(编号1~n)和n-1条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
输入格式
第一行包含整数n,表示树的结点数。
接下来n-1行,每行包含两个整数a和b,表示点a和点b之间存在一条边。
输出格式
输出一个整数m,表示重心的所有的子树中最大的子树的结点数目。
数据范围
1≤n≤1051≤n≤105
输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10,M = N*2;
//h表示链表头,e存储的是所有的边,ne表示所有的next指针是多少,相当与n个单链表
int h[N],e[M],ne[M],idx,n;
int ans = N;//全局的答案存储最小的最大值
//深度优先搜索和宽度优先搜索每个点只会遍历一次
bool st[N];//存一下那些点已经被遍历过了,就不要再遍历他了
void add(int a,int b){//a前插入b
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
//树和图的深度优先搜索的代码 时间复杂度是O(n + m),因为点数和边数呈线性关系
//u表示已经遍历到这个节点了
//以u为根的子树中点的数量
int dfs(int u){
st[u] = true;//首先先标记下当前这个点已经被搜索过了
//记录当前子树的大小
int sum = 1;
int res = 0;//表示当前连通块的最小值的最大值
//遍历下u的所有的初边
for(int i = h[u];i != -1;i = ne[i]){
// 存储当前结点对应图里边结点的编号是多少
int j = e[i];
//如果当前点没有做过的话,就一直搜,一条路走到黑
if(!st[j]) {
//表示当前子树的大小
int s = dfs(j);
//当前的子树也算是一个连通块
res = max(res,s);
//当前子树也是我们的子树的一部分
//s为根的子树是以u为根节点的子树的一部分
sum += s;
}
}
res = max(res,n - sum);
// cout << u << " " << sum;
//最后res存的就是删除当前这个点之后所存储的最大的点数了
ans = min(res,ans);
return sum;
}
int main(){
//头结点指向-1,n给单链表的头结点指向-1
memset(h,-1,sizeof h);
cin >> n;
for(int i = 0;i < n - 1;i++){
int a,b;
cin >> a >> b;
add(a,b),add(b,a);
}
dfs(1);//从第一个点开始搜索
cout << ans;
}
浙公网安备 33010602011771号