#P1453. 2023.08.13-第二题-米小游的有根树
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 844
            Accepted: 181
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              米哈游
                                
            
                        
              时间 :2023年8月13日
                              
                      
          
 
- 
                        算法标签>DFS          
 
2023.08.13-第二题-米小游的有根树
思路:DFS
以 1 号点为根,求出从 1 号点到所有点的距离,如果距离小于等于 k ,则将这个点加入到答案中。
此外,对于一个叶子节点,如果其距离 d 小于 k ,则说明还可以在这个叶子下添加 k−d 个点,这些点成一条链。
所以,在进行以 1 号点为根的树的遍历的过程中,即可获得从 1 号点到每个点的距离,同时进行判断和答案计算即可。
时间复杂度:O(n)
代码
C++
#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, k;
    cin >> n >> k;   
    // 建图
    vector<vector<int>> g(n);
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    const int INF = 0x3f3f3f3f;
    long long ans = 0;
    vector<int> dist(n, INF);
    // 计算1号点到每个点的距离,1号点到自己的距离为 0
    dist[0] = 0;
    function<void(int,int)> dfs = [&](int u, int fa) {
        // 如果1号点到u+1点的距离 <= k,则答案加1
        if (dist[u] <= k) {
            ans += 1;
        }
        // 如果1号点到叶子的距离 < k,则还可以再这个叶子下加 k - dist[u] 个
        if (u != 0 && g[u].size() == 1 && dist[u] < k) {
            ans += k - dist[u];
        }
        // 继续遍历子树 v 
        for (int v: g[u]) {
            if (v == fa) continue;
            dist[v] = dist[u] + 1;
            dfs(v, u);
        }
    };
    
    dfs(0, -1);
    cout << ans << "\n";
    return 0;
}
python
def dfs(u, fa):
    global ans
    # 如果1号点到u+1点的距离 <= k,则答案加1
    if dist[u] <= k:
        ans += 1
    # 如果1号点到叶子的距离 < k,则还可以再这个叶子下加 k - dist[u] 个
    if u != 0 and len(g[u]) == 1 and dist[u] < k:
        ans += k - dist[u]
    # 继续遍历子树 v 
    for v in g[u]:
        if v == fa:
            continue
        dist[v] = dist[u] + 1
        dfs(v, u)
n, k = map(int, input().split())
# 建图
g = [[] for _ in range(n)]
for _ in range(1, n):
    u, v = map(int, input().split())
    u -= 1
    v -= 1
    g[u].append(v)
    g[v].append(u)
INF = int(1e9)
ans = 0
dist = [INF] * n
# 计算1号点到每个点的距离,1号点到自己的距离为 0
dist[0] = 0
dfs(0, -1)
print(ans)
Java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
    static List<List<Integer>> g;
    static int[] dist;
    static int n, k;
    static long ans;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        k = scanner.nextInt();
        
        // 建图
        g = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            g.add(new ArrayList<>());
        }
        for (int i = 1; i < n; i++) {
            int u = scanner.nextInt() - 1;
            int v = scanner.nextInt() - 1;
            g.get(u).add(v);
            g.get(v).add(u);
        }
        final int INF = 0x3f3f3f3f;
        ans = 0;
        dist = new int[n];
        for (int i = 0; i < n; i++) {
            dist[i] = INF;
        }
        // 计算1号点到每个点的距离,1号点到自己的距离为 0
        dist[0] = 0;
        dfs(0, -1);
        System.out.println(ans);
    }
    static void dfs(int u, int fa) {
        // 如果1号点到u+1点的距离 <= k,则答案加1
        if (dist[u] <= k) {
            ans++;
        }
        // 如果1号点到叶子的距离 < k,则还可以再这个叶子下加 k - dist[u] 个
        if (u != 0 && g.get(u).size() == 1 && dist[u] < k) {
            ans += k - dist[u];
        }
        // 继续遍历子树 v 
        for (int v : g.get(u)) {
            if (v == fa) {
                continue;
            }
            dist[v] = dist[u] + 1;
            dfs(v, u);
        }
    }
}
        题目内容
米小游有一个 n 个节点的树,树根编号为 1 。
米小游可以在叶子节点上添加一个新的儿子节点,添加后,添加的节点变成了新的叶子节点。
若干次操作后,米小游想问你距离树根不超过 k 的节点最多可以有多少个。
输入描述
第一行,一个正整数n 表示树中节点个数,k 表示不超过树根的距离,
接下来 n−1 行,每行输入两个整数 u 和 v ,表示节点 u 和 v 之间有一条边。
$1 \leq n \leq 10^5, 1\leq k\leq 10^9, 1\leq u,v\leq n$
输出描述
一个整数,表示若干次操作后距离树根不超过 k 的节点最大数量。
样例
输入
4 2
1 2
1 3
1 4
输出
7
说明
若干次操作后,最终的树如下,此时有 7 个点距离 1 号点的距离小于等于 2
        1
      / | \
     2  3  4
       ↓↓↓
        1
      / | \
     2  3  4
    /   |   \
   5    6    7