砍树
题目描述
给出一个树形图(“tree-shaped” network),有N个顶点。如果删除树上某一个顶点,整棵树就会分割成若干个部分。显然,每个部分内部仍保持连通性。
现在问:删除哪个点,使得分割开的每个连通子图中点的数量不超过N/2?如果有很多这样的点,就按升序输出。
输入
第1行:1个整数N,表示顶点数。顶点编号1-N。 接下来n-1行每行两个整数x,y,表示x到y有一条边。
输出
若干行,每行1个整数,表示一个符合条件的顶点的编号。如果没有顶点符合条件,则仅在第1行输出“NONE”。
样例输入
10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
样例输出
3
8
提示
【数据范围及约定】
对于50%的数据,满足1≤N≤10000
对于100%的数据,满足1≤N≤1000000
直接随机找到一个点往下搜索就行。如果一个节点的子儿子和他自己正好N/2个,他是,如果他及他的子儿子大于等于N/2,而且儿子中没有大于等于N/2的也是一个,只有这两种情况。
1 #define MAXN 1000010UL 2 3 #include<cstdio> 4 #include<algorithm> 5 //#include<vector> 6 using namespace std; 7 int n,head[MAXN],cnt,md; 8 int ans[MAXN],ge,son[MAXN]; 9 bool vis[MAXN]; 10 struct Node{ 11 int en,to; 12 }eda[MAXN<<1]; 13 void Add(int x,int y){ 14 eda[++cnt].en=y; 15 eda[cnt].to=head[x]; 16 head[x]=cnt; 17 } 18 void dfs(int x){ 19 vis[x]=1; 20 bool flag=0; 21 bool er=0; 22 son[x]++; 23 for(int i=head[x];i;i=eda[i].to){ 24 int y=eda[i].en; 25 if(!vis[y]){ 26 dfs(y); 27 if(son[y]>=md){ 28 flag=1; 29 if(son[y]==md) er=1; 30 } 31 son[x]+=son[y]; 32 } 33 } 34 if(!flag&&son[x]>=md){ 35 ans[++ge]=x; 36 } 37 if(flag){ 38 if(er){ 39 ans[++ge]=x; 40 } 41 } 42 } 43 int main(){ 44 freopen("tree.in","r",stdin); 45 freopen("tree.out","w",stdout); 46 scanf("%d",&n); 47 md=n>>1; 48 int x,y; 49 for(int i=1;i<n;i++){ 50 scanf("%d%d",&x,&y); 51 Add(x,y); 52 Add(y,x); 53 } 54 dfs(1); 55 if(ge==0){ 56 printf("NONE"); 57 return 0; 58 } 59 sort(ans+1,ans+ge+1); 60 for(int i=1;i<=ge;i++){ 61 if(ans[i]!=ans[i-1]) 62 printf("%d\n",ans[i]); 63 } 64 }