AcWing 1079. 叶子的颜色 java树形DP


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

⭐ 假设:每个子节点都涂了颜色,然后再一个个删,得出最小涂色数
⭐ 思路:由于题目规定根节点度数 >1 ,染根节点可以满足的题目条件数 也必 >1(父节点影响子节点),所以染 根节点 稳赚不亏
🐷 关键:
⭐ 根节点非黑即白 (最优解)
⭐ 根节点任意并不影响整体叶子节点的颜色 -> 不影响最小染色节点数
import java.util.Arrays;
import java.util.Scanner;
public class Main
{
static int N = 10010, n, m, idx, INF = (int) 1e8;
static int M = 2 * N;// 无向图边是点的两倍
static int[] c = new int[N];// 记录叶子节点的颜色\
static int[] h = new int[N];
static int[] e = new int[M];
static int[] ne = new int[M];
static int[][] f = new int[N][2];
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
m = sc.nextInt();
n = sc.nextInt();
Arrays.fill(h, -1);
// 输入叶子节点的颜色
for (int i = 1; i <= n; i++)
c[i] = sc.nextInt();
// 加边( m-1条边而不是 m 条边)
for (int i = 0; i < m - 1; i++)
{
int a = sc.nextInt();
int b = sc.nextInt();
add(a, b);
add(b, a);
}
// System.out.println("bug");
// 初始化 dp数组
for (int i = 1; i <= n; i++)
{
// if (i <= n)
// {
// f[i][c[i]] = 1;
// f[i][1 - c[i]] = INF;
// } else
// f[i][0] = f[i][1] = 1;
f[i][c[i]] = 1;
f[i][1 - c[i]] = INF;
}
dfs(n + 1, -1);// 1~n 是叶子节点,从第一个根节点按拓扑序搜索
System.out.println(Math.min(f[n + 1][0], f[n + 1][1]));
}
private static void dfs(int u, int fa)
{
if (u <= n)//到达叶子节点
return;
f[u][0] = f[u][1] = 1;
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j == fa)
continue;
dfs(j, u);
f[u][0] += Math.min(f[j][0] - 1, f[j][1]);
f[u][1] += Math.min(f[j][1] - 1, f[j][0]);
}
}
// 加一条 a 指向 b 的边
private static void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
}

浙公网安备 33010602011771号