POJ 2378 Tree Cutting

POJ2378

题 意:输入包含n个点的无向图,问删除其中一个点,是否能使剩下的图,每个图中所包含的点均小于n/2。求所有满足要求的点,并按从小到大的顺序排队。
数据范围:
1<=n<=1000
样例输入:

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

样例输出:

3
8

思 路:我们需要维护每一个点切割后,所产生的块中所包含的点最大d[u]是多少,它包括切割该点后,改点个分支孩子节点,父亲节点。
那么怎么维护呢?首先建树,dfs建树。其实在建树的同时就可以维护,当前节点包含的子节点个数,以及d[u],维护当前节点所包含的节点数看
codeforce-1006E
关键点,其实这题可以分析出这么写的。也就是建树。维护d[u]
收获:学习了怎么dfs建树,加深了对dfs的理解 学习了怎么维护各分支子节点以及父节点的最大值.
刘汝佳建树模板

vector<int>G[MAXN];
int father[MAXN];//记录i结点的父亲是谁、 
void read_tree(){   //读入 
    int u,v;
    scanf("%d",&n);
    for(int i=1; i<n; ++i){
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
}
//转化过程、
void dfs(int u, int fa){    //递归转化为以u为根的子树,u的父节点为fa 
    int d = G[u].size();    //结点u的相邻点个数、 
    for(int i=0; i<d; ++i){
        int v = G[u][i];    //提取u的相邻点 
        if(v!=fa)   dfs(v, father[v] = u);  //把v的父节点设为u,然后递归转化为以v为根节点的子树 
    }
}

AC代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4+5;
vector<int>G[maxn];
int father[maxn];
int d[maxn];
int n;
//这是一段比较好的代码
int dfs(int u,int v){
    int sum = 1,mson = 0;
    d[u] = 0;
    for(int i=0;i<G[u].size();i++){   //维护个分支子节点和父节的最大值
        int to = G[u][i];
        if(to == v)continue;
        int ans = dfs(to,father[to] = u);
        mson = max(mson,ans);
        sum += ans;
    }
    d[u] = max(mson,n-sum);
    return sum;    //只需要传递当前节点的子节点的个数就好
}
int main() {
    while(~scanf("%d",&n)){
        memset(d,0,sizeof(d));
        for(int i=0;i<maxn;i++)G[i].clear();
        int s,t;
        for(int i=2;i<=n;i++){
            scanf("%d %d",&s,&t);
            G[s].push_back(t);
            G[t].push_back(s);
        }
        dfs(1,0);
        for(int i=1;i<=n;i++){
            if(d[i]*2 <= n){
                printf("%d\n",i);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/81125816