树的重心

定义:

1.找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心。
2.以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

性质:

1.树中所有点到某一点距离之和中,到重心的距离和最短。

2.把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。
3.把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

DP的记忆化搜索来求解。

const int maxn=500005;
int tot=0,n;
int ans,size;
int sx[maxn],head[maxn];
int vis[maxn];
struct edge
{
    int to,next;
} eg[maxn];
void add(int u,int v)
{
    eg[tot].to=v;
    eg[tot].next=head[u];
    head[u]=tot++;
}
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
}
void dfs(int u)
{
    vis[u]=1;
    sx[u]=1;
    int tmp=0;
    for(int i=head[u]; i!=-1; i=eg[i].next)
    {
        int v=eg[i].to;
        if(!vis[v])
        {
            dfs(v);
            sx[u]+=sx[v];
            tmp=max(tmp,sx[v]);
        }
    }
    tmp=max(tmp,n-sx[u]);
    if(size>tmp||size==tmp&&ans>u)
    {
        ans=u;
        size=tmp;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        int u,v;
        scanf("%d",&n);
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        size=INF;
        dfs(1);
        printf("%d %d\n",ans,size);
    }
}

 

### 关于树的重心的洛谷题目解析 #### 树的重心定义 树的重心是指在一棵树中找到一个节点,使得当这个节点作为根时,其所有的子树大小都不超过整棵树的一半。通过计算每个节点的子树大小并判断条件是否满足来确定重心。 #### 解决方案概述 解决树的重心问题通常涉及以下几个方面: 1. **DFS 遍历**:用于计算每个节点的子树大小以及验证当前节点是否为重心。 2. **动态规划 (DP)**:对于某些复杂场景下的树形 DP 可能需要用到状态转移方程[^2]。 3. **剪枝优化**:在回溯或其他搜索过程中应用剪枝策略以提升效率[^4]。 以下是基于上述理论的一个典型实现: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; vector<int> tree[MAXN]; int n, size_subtree[MAXN], ans; // DFS 函数用来计算子树大小寻找重心 void dfs(int u, int parent) { size_subtree[u] = 1; // 初始化子树大小为自己本身 bool is_centroid = true; // 假设当前节点可能是重心 for(auto v : tree[u]) { if(v != parent){ dfs(v, u); size_subtree[u] += size_subtree[v]; // 累加子树大小 // 如果某个子树过大,则该节点不可能成为重心 if(size_subtree[v] > n / 2) is_centroid = false; } } // 判断剩余部分是否也符合条件 if(n - size_subtree[u] > n / 2) is_centroid = false; if(is_centroid && !ans) { // 找到第一个重心就停止查找 ans = u; } } int main(){ cin >> n; for(int i=1;i<n;i++){ int a,b; cin>>a>>b; tree[a].push_back(b); tree[b].push_back(a); } dfs(1,0); // 开始从任意一点出发找重心 cout << ans; } ``` 此代码片段展示了如何利用深度优先搜索(DFS)技术来定位一棵无向连通图中的重心位置。 #### 数据结构与算法分析 - 使用邻接表存储树结构以便快速访问相邻节点。 - 动态更新各节点对应的子树规模,并依据这些数据判定候选重心的有效性。 #### 进一步扩展思考方向 为了加深理解或者应对更复杂的变体挑战,可以从如下几个角度展开探索: 1. 如何处理带权边的情况? 2. 当存在多个可能的重心时应返回哪一个? 3. 能否在线性时间内完成整个过程?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值