树形dp基础知识(树的dfs序,树的深度,树的直径,树的重心)

一、树的dfs序

1、思路

对数进行深度优先搜索时,对于每个节点,在刚进入递归后以及即将回溯前各记录一次该点的编号,最后产生的长度为2N的节点序列就为树的DFS序。——摘自算法竞赛进阶指南(李耀东)

2、性质

  1. 每个节点的编号出现两次,一次为 L [ x ] , R [ x ] L[x],R[x] L[x],R[x]
  2. 闭区间 [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]],就是以x为根的子树的DFS序。

3、Code

const int N = 1e5;
int a[N<<1],cnt = 0;//a记录dfs序
bool vis[N];
void dfs(int u){
    a[++cnt] = u;
    vis[x] = 1;
    for(int i = head[u], ~i ;i = e[i].next){
        int v = e[i].v;
        if(vis[v]) continue;
        dfs(v);
    }
    a[++cnt] = u;
}

二、树的深度

1、Code(自上而下)

const int N = 1e5;
int dis[N];//深度
void dfs(int u,int fa){
    for(int i = head[u]; ~i ; i = next[i].next){
        int v = e[i].v;
        if(fa == v) continue;
        dis[v] = dis[u] + 1;
        dfs(v,u);
    }
}

三、树的直径

1、思路

  1. 设两个 d p dp dp d p 1 [ x ] dp1[x] dp1[x] x x x点到叶子结点的最长距离, d p 2 [ x ] dp2[x] dp2[x] x x x点到叶子结点的次长距离。
  2. 树的直径则为 d p 1 [ x ] + d p 2 [ x ] dp1[x]+dp2[x] dp1[x]+dp2[x]

2、Code(自底而上)

const int N = 1e5+5;
int dp1[N],dp2[N],maxx = 0;//最大距离和次大距离,maxx树的直径
void dfs(int u,int fa){
    for(int i = head[u]; ~i ; i = e[i].next){
        int v = e[i].v;
        if(v == fa) continue;
        dfs(v,u);
        if(dp1[u] < dp1[v] + 1){//更新最大距离
            dp2[u] = dp1[u];
            dp1[u] = dp1[v] + 1;
        }
        else if(dp2[u] < dp1[v] + 1){//更新次大距离
            dp2[u] = dp1[v] + 1;
        }
        maxx = max(maxx,dp1[u]+dp2[u]);//树的直径
    }
}

四、树的重心

1、定义

删除节点 x x x后产生的子树中,最大的一棵树的大小最小,则x称为树的重心。

2、思路

  1. 设每个节点 x x x为根的子树大小 s i z e [ x ] size[x] size[x],设节点 x x x的k个子节点为 y 1 − y 2 y1-y2 y1y2 s i z e [ x ] = s i z e [ y 1 ] + s i z e [ y 2 ] + . . . . . . + s i z e [ y k ] + 1 size[x] = size[y1]+size[y2]+......+size[yk]+1 size[x]=size[y1]+size[y2]+......+size[yk]+1
  2. 自底向上搜索,记录 x x x节点的子节点最大值max_part,并比较max_part与 n − s i z e [ x ] n-size[x] nsize[x](代表从整棵树中删去根节点为x的子树)的大小。
  3. 如果max_part小的话,就更新答案。

3、性质

  1. 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。
  2. 把两棵树通过一条边相连,新树的重心在原来两棵树重心的连线上。
  3. 一棵树添加或删除一个节点,树的重心最多只移动一条边的位子。
  4. 一棵树最多有两个重心,且相邻。

4、Code(自底向上)

int size[N];
int n, ans, pos;//ans是max_part,pos是树的重心。
void dfs(int u,int fa){
    size[u] = 1;
    int max_part = 0;
    for(int i = head[u]; ~i; i = e[i].next){
        int v = e[i].v;
        if(v == fa) continue;
        dfs(v,u);
        size[u] += size[v];//从子节点向父亲节点递推
        max_part = max(max_part, size[v]); 
    }
    max_part = max(max_part,n - size[u]);
    if(max_part < ans){
        ans = max_part;
        pos = u;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值