ICPC Southeastern European Regional (SEERC 2018) C. Tree

Problem Description

You are given a tree of n vertices, each with a unique number from 1 to n. A vertex has a color, black or white.

Choose exactly m black vertices so that the length of the longest path between any of them is minimal.

Input

The first line contains two integers n and m (1 ≤ m ≤ n ≤ 100) — the number of vertices and the number of black vertices you have to choose.

The fourth line contains n integers p1,p2,...,pn(0≤pi≤1)p_1, p_2, . . . , p_n (0 ≤ p_i ≤ 1)p1,p2,...,pn(0pi1). If the pip_ipi = 1, then the i-th vertex is black; otherwise, it is white. It is guaranteed that the number of black vertices is at least m.

Each of the next n − 1 lines contains two integers viv_ivi and ui(1≤vi,ui≤n)u_i (1 ≤ v_i, u_i ≤ n)ui(1vi,uin) meaning that there is an edge between
viv_ivi and uiu_iui.

It is guaranteed that the input graph is a tree.

Output

Print a single integer — the answer to the task.

Sample Input

6 3
1 1 0 1 1 1
1 2
1 3
1 4
3 5
3 6

Sample Output

2

Sample Input2

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

Sample Output2

5

Note

In the first example, the only option is to choose 1, 2, and 4. The maximum distance will be 2.

In the second example, you can choose 1, 3, 8, and 9. The maximum distance will be between 3 and 9.

Solution

最常见解法就是树形dp了
下面这篇博客写的非常详细:
https://blog.csdn.net/qq_37025443/article/details/89084072

AC Code

/*
 * Copyright (c) 2019 Ng Kimbing, HNU, All rights reserved. May not be used, modified, or copied without permission.
 * @Author: Ng Kimbing, HNU.
 * @LastModified:2019-07-30 T 11:24:32.018 +08:00
 */

package ACMProblems.DynamicProgramming.TreeDp;

import java.util.ArrayList;
import java.util.Arrays;

import static ACMProblems.ACMIO.nextInt;
import static ACMProblems.ACMIO.out;

public class Tree {
    private static int maxn = 105;
    private static ArrayList<Integer>[] G = new ArrayList[maxn];
    private static int n, m;
    private static int[] isBlackPoint = new int[maxn];
    private static int[][] dp = new int[maxn][maxn];

    private static void dfs(int cur, int pre, int dis) {
        for (int nx : G[cur])
            if (nx != pre)
                dfs(nx, cur, dis);
        if (isBlackPoint[cur] == 1)
            dp[cur][0] = 1;
        for (int i = 1; i <= dis; i++) {
            int limit = Math.min(dis - 1 - i, i - 1), sum;
            sum = getSumOfAllChildren(cur, pre, limit);
            //最大距离不超过i-1, 那么必定不超过i
            dp[cur][i] = dp[cur][i - 1];
            for (int nx : G[cur]) {
                if (nx == pre)
                    continue;
                int tmp = dp[nx][i - 1];
                if (limit >= 0)
                    tmp += sum - dp[nx][limit];
                dp[cur][i] = Math.max(dp[cur][i], isBlackPoint[cur] + tmp);
            }
        }
    }

    private static int getSumOfAllChildren(int cur, int pre, int limit) {
        int sum = 0;
        if (limit >= 0)
            for (int nx : G[cur])
                if (nx != pre)
                    sum += dp[nx][limit];
        return sum;
    }

    private static boolean check(int dis) {
        for (int[] aDp : dp) Arrays.fill(aDp, 0);
        dfs(1, -1, dis);
        for (int i = 1; i <= n; ++i)
            if (dp[i][dis] >= m)
                return true;
        return false;
    }

    public static void main(String[] args) throws Exception {
        n = nextInt();
        m = nextInt();
        for (int i = 1; i <= n; i++) {
            isBlackPoint[i] = nextInt();
            G[i] = new ArrayList<>();
        }
        for (int i = 0; i < n - 1; i++) {
            int u = nextInt();
            int v = nextInt();
            G[u].add(v);
            G[v].add(u);
        }
        int l = 0, r = n;
        check(4);
        while (r > l) {
            int mid = (l + r + 1) >> 1;
            if (check(mid - 1))
                r = mid - 1;
            else l = mid;
        }
        out.println(r);
        out.flush();
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值