![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
题目描述 有一个NN个节点的无根树,各节点编号为1..N1..N,现在要求你删除其中的一个点,使分割开的连通块中节点个数都不超过原来的一半多。 输入格式 第一行:一个整数N(1≤N≤10,000)N(1≤N≤10,000)。 后面有N−1N−1行:每行两个整数 XX 和 YY,表示一个边连接的两个节点号。 输出格式 输出所有可能选择的点。如果有多个节点,按编号从小到大输出,每个一行。 如果找不到这样的点,输出一行:"NONE". 样例一 input 10 1 2 2 3 3 4 4 5 6 7 7 8 8 9 9 10 3 8 output 3 8 样例说明 删除3号或8号节点,则分枝最多有5个节点 限制与约定 时间限制:1s1s 空间限制:256MB
这道题是树的重心裸题,是为树hs做准备的
思路就是搜索一遍,然后如果这个点的max(size【son】,n-size【now】)小于等于n>>1,那么它就是重心
复杂度O(n);
1 #include<bits/stdc++.h> 2 #define N 10011 3 #define clear(a,val) memset(a,val,sizeof(a)) 4 using namespace std; 5 int n,x,y,cnt=1,pp; 6 int head[N],nxt[N*2],to[N*2],size[N],ans[N]; 7 inline void add(int u,int v) 8 {nxt[cnt]=head[u],to[cnt]=v,head[u]=cnt++;} 9 inline void initandbuild() 10 { 11 clear(head,-1); 12 scanf("%d",&n); 13 for(int i=1;i<n;i++) 14 { 15 scanf("%d%d",&x,&y); 16 add(x,y),add(y,x); 17 } 18 } 19 int dfs(int now,int fa) 20 { 21 size[now]=1;int ma=-1; 22 for(int i=head[now];i!=-1;i=nxt[i]) 23 { 24 int t=to[i]; 25 if(t==fa)continue; 26 size[now]+=dfs(t,now); 27 ma=max(ma,size[t]); 28 } 29 ma=max(ma,n-size[now]); 30 if(ma<=(n>>1))ans[++pp]=now; 31 return size[now]; 32 } 33 int main() 34 { 35 initandbuild(); 36 dfs(1,-1); 37 sort(ans+1,ans+pp+1); 38 for(int i=1;i<=pp;i++) 39 printf("%d ",ans[i]); 40 if(!pp)puts("NONE"); 41 return 0; 42 }