Description

现在有一棵树T,有N个节点,我们想通过去掉一个节点p来把T分割成更小的树,并且满足每个小树中的节点数不超过n/2。

请根据输入的树来输出所有可能的p的号码。

Input Format

第1行:一个整数N,代表有N个节点,且每个节点的编号为1,2,...,N。

第2~N行:每行两个整数x,y,代表节点x和节点y之间连通。

Output Format

从小到大一次输出满足条件的p的号码,每行1个可行解。

Input Sample

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

Output Sample

3
8


想法其实很简单...
首先用邻接表存储整个图(注意, n个点 n-1个边的图除了二叉树有很多种可能.....)
然后 把每个点的每个分支的节点数计算出来 最后进行判断输出即可
//递归的描述很简单
遍历所有的点,不断的递归调用getComponent函数即可,指定源头和分支首元素。
代码如下(没用Vector):
#include <iostream>
#define MaxN 10000+10
using namespace std;
 
int n;
int connect[MaxN][200]={0}; 
int len_c[MaxN]={0};
int seg[MaxN][200]={0}; 
bool caled[MaxN] = {0};  

void init(){
    cin>>n;
    //记录连通情况 O(n)
    for (int i = 0; i < n-1; ++i)
    {
        int x,y;
        cin>>x>>y;
        connect[x][len_c[x]++] = y;
        connect[y][len_c[y]++] = x;
    }
    //初始化所有只有一个分支的点的分割情况 
    for (int i = 1; i <= n; ++i) if(len_c[i]==1)
    {
        seg[i][0] = n-1;
        caled[i] = true;
    }
    //初始化有两个分支 且至少有一个分支只有一个元素的节点的分割情况
    for (int i = 1; i <= n; ++i) if(len_c[i]==2)
    {
        if(len_c[connect[i][0]]==1){
            seg[i][0] = 1;
            seg[i][1] = n-2;
            caled[i] = true;
        }
        if(len_c[connect[i][1]]==1){
            seg[i][1] = 1;
            seg[i][0] = n-2;
            caled[i] = true;
        }
        
    }
    //
}
 
 
//计算与s相连的 以x开头的那一个分支有多少个节点
int getComponent(int s, int x){
    int len = len_c[x];
    int res = 1;//肯定有x本身    
    if(caled[x]){
        for (int i = 0; i < len; ++i) if(connect[x][i]!=s)
            res += seg[x][i];
    }else{//说明x的seg情况没有初始化过 
        int tmp = 0;
        for (int i = 0; i < len-1; ++i)
        { 
            seg[x][i] = getComponent(x,connect[x][i]);
            tmp += seg[x][i];
            if(connect[x][i]!=s)
                res += seg[x][i];
        }
        seg[x][len-1] = n-1-tmp;
        caled[x] = true;
    }
    return res;
} 
 
void Build(){
    //去构建所有的seg
    for (int i = 1; i <= n; ++i) if(!caled[i])
    { 
        int len = len_c[i];
        int tmp = 0;
        for (int j = 0; j < len-1; ++j){
            //递归计算 i的以j开头的那个分支有多少个元素
            seg[i][j] = getComponent(i,connect[i][j]);
            tmp += seg[i][j];
        }
        seg[i][len-1] = n-1-tmp;//最后一个分支可以用补集的思想
        caled[i] = true;
    }
}
 
void Output(){
    for (int i = 1; i <= n; ++i)
    {
        bool ok = true;
        for (int j = 0; j < 3; ++j) if(seg[i][j]>n/2)
        {
            ok = false;
            break;
        }
        if(ok)
            cout<<i<<endl;
    }
}
 
int main(int argc, char const *argv[])
{
    init(); 
    Build();
    Output(); 
 
    return 0;
}
递归

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-01-04
  • 2022-12-23
  • 2022-12-23
  • 2021-07-12
  • 2021-11-05
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-11-11
  • 2022-12-23
  • 2021-07-02
  • 2021-09-07
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案