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++;
	}

}

posted @ 2023-03-24 15:15  兑生  阅读(26)  评论(0)    收藏  举报  来源
Live2D