题目
给定一颗树,树中包含n个结点(编号1~n)和n-1条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
输入格式
第一行包含整数n,表示树的结点数。
接下来n-1行,每行包含两个整数a和b,表示点a和点b之间存在一条边。
输出格式
输出一个整数m,表示将重心删除后,剩余各个连通块中点数的最大值。
数据范围
1≤n≤105
输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4
dfs模板
变量定义
int h[i]
:编号为i的头指针int e[i]
:指针i所表示的编号int ne[i]
:指针i的下一个指针boolean st[i]
:编号为i是否被使用过index
:用来开辟空间为新建的结点(这个并不是编号)res
: 表示所求的结果,在递归过程不断迭代.
模板
dfs(int k){//搜索编号k
st[k]=true;
for(int i=h[k];i!=0;i=ne[i]){//找到k的子节点
int j=e[i];
dfs(j);//搜索每一个k的子节点
}
}
源代码
import java.util.*;
class Main{
static int N=100010;
static int index=0;
static int[] e=new int[2*N];
static int[] ne=new int[2*N];
static int[] h=new int[N];
static int ans=N;
static boolean[] st=new boolean[N];
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=n-1;
while(m-->0){
int a=sc.nextInt();
int b=sc.nextInt();
add(a,b);
add(b,a);
}
dfs(1,n);
System.out.println(ans);
}
public static void add(int a,int b){
index++;
e[index]=b;
ne[index]=h[a];
h[a]=index;
}
public static int dfs(int k,int n){//返回:编号为k的结点下有多少子节点(包扩自己),ps这个编号不是index
st[k]=true;
int sum=1;
int res=0;
for(int i=h[k];i!=0;i=ne[i]){
int j=e[i];
if(st[j]==false){
int s=dfs(j,n);
sum+=s;
res=Math.max(res,s);
}
}
res=Math.max(res,n-sum);
ans=Math.min(ans,res);
return sum;
}
}
代码自问自答
Q:为什么e[]
/ne[]
数组的空间是2N,h[]
/st[]
数组的空间是N?
A:因为最多一共有N个节点,每个节点配一个链,因此头结点就是N个,而st[]数组表示的是某一个编号的结点是否被遍历过,因此主要N个即可.
但是由于是无向图,因此边的个数其实是向量的两倍,而其实每建一个向量,都需要开辟一个节点(也就是index++)来存储,最多就是2N个节点. 换句话来说,每一个有向边就需要一个节点来存储.一个无相边是两个有向边.
Q:为什么要标记结点被遍历过呢?
A:主要问题出在无向图!因为无向图相当于两个有向图,而如果不标记节点的话,很有可能在遍历时在两个结点间不停的遍历.
Q:为什么dfs函数返回的值不是res而是sum呢?
A:这是一种特别的设计方式,递归函数的返回值并不是自己想要的答案,但是在递归函数的递归过程中,答案在不停的迭代,递归完成时,只需要输出迭代后的答案即可.
本题的设计方式:
函数返回的值是sum
:当前编号的结点下所有结点的个数.求法是遍历当前节点的所有未标记的子节点,调用递归函数返回每个子节点的个数,并将这些值加和存入sum变量中.
同时为了找到删除当前节点的各个部分的结点个数的最大值(其实就是找到子节点个数和n-sum的较大值),我们用res变量存储每个遍历子节点过程中的较大值,当把所有子节点都遍历到,res保存的其实就是这些子节点中,最多的结点数了.
之前存储的sum值就是为了帮助完成最后一步—n-sum和res值的较大值赋给res,自此,res变量保存的就是删除结点k的子节点个数的最大值.
又因为我们要看删除各个结点的res的最小值,因此我们又定义了ans变量在递归函数中,这样当所有递归函数结束时,ans就是我们想要的最终解.