给一棵树,求删除一个节点后最大连通分量最小的点
树形dp
d[i][0] 表示 以i为根节点的子树的总结点数(i不算)
d[i][1] 表示以i为根节点的树的最大的子树的结点数
d[i][2] 表示整个树除了子树i外的结点数
则所求的就是要max(d[i][1],d[i][2])尽可能的小
最后该题卡STL,所以要用链式向前星
最后链式向前星的next和to数组要开 N*2 那么大,存双向边~
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N =50010;
int n,u,v,d[N][3],mam = 1e9;
int h[N],net[N*2],to[N*2],tot;
void add(int u,int v){
to[++tot] = v;
net[tot] = h[u];
h[u] = tot;
}
void dfs(int u,int fa){
d[u][0] = 0;
d[u][1] = 0;
for(int i = h[u];i;i = net[i]){
int v = to[i];
if(v ==fa) continue;
dfs(v,u);
d[u][0] += d[v][0] + 1;
d[u][1] = max(d[u][1],d[v][0] + 1);
}
d[u][2] = n - 1 - d[u][0];
}
int main(){
while(~scanf("%d",&n)){
tot = 0;
memset(h,0,sizeof(h));
mam = 1e9;
for(int i = 0;i<n-1;i++) {
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,-1);
for(int i = 1;i<=n;i++){
if(max(d[i][1],d[i][2])<mam)
mam = max(d[i][1],d[i][2]);
}
for(int i = 1;i<=n;i++){
if(max(d[i][1],d[i][2]) == mam) printf("%d ",i);
}
printf("\n");
}
return 0;
}