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(0≤pi≤1). 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(1≤vi,ui≤n) 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();
}
}