[DFS]JZOJ 1301 treecut

Description

  有一个N个节点的无根树,各节点编号为1..N,现在要求你删除其中的一个点,使分割开的连通块中节点个数都不超过原来的一半多。
 

Input

  第一行:一个整数N (1 <= N <= 10,000)。   后面有N-1行:每行两个整数 X 和 Y,表示一个边连接的两个节点号。

Output

  输出所有可能选择的点。如果有多个节点,按编号从小到大输出,每个一行。 如果找不到这样的点,输出一行:"NONE".
 

Sample Input

10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
 

Sample Output

3 8
 

Data Constraint

 
 

Hint

样例说明:   删除3号或8号节点,则分枝最多有5个节点

分析

很容易想到类似于树的重心的东西,只要这个点所有子树大小不超过一半即可

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e4+10;
struct Graph {
    int v,nx;
}g[2*N];
int cnt,list[N],sz[N],ans[N];
int n;

void Add(int u,int v) {
    g[++cnt]=(Graph){v,list[u]};list[u]=cnt;
    g[++cnt]=(Graph){u,list[v]};list[v]=cnt;
}

void DFS(int u,int fa) {
    bool b=1;
    sz[u]=1;
    for (int i=list[u];i;i=g[i].nx)
        if (g[i].v!=fa) {
            DFS(g[i].v,u);
            sz[u]+=sz[g[i].v];
            if (sz[g[i].v]>n/2) b=0;
        }
    if (n-sz[u]<=n/2&&b) ans[++cnt]=u;
}

int main() {
    scanf("%d",&n);
    for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),Add(u,v);
    cnt=0;DFS(1,-1);
    sort(ans+1,ans+cnt+1);
    for (int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
    if (!cnt) printf("NONE");
    printf("\n");
}
View Code

 

posted @ 2019-06-04 19:42  Vagari  阅读(211)  评论(0编辑  收藏  举报