题目描述
给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数
唯一的限制条件是相临的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小。
输入格式
先给出一个数字N,代表树上有N个点,N<=10000
下面N-1行,代表两个点相连
输出格式
最小的总权值
输入输出样例
输入 #1
10
7 5
1 2
1 7
8 9
4 1
9 7
5 6
10 2
9 3
输出 #1
14
思路
可以证明(1、2、3、4)就足够赋值了,因为要取最小权值。(证明略,这里有证明)
-
d p [ i ] [ j ] {dp[i][j]} dp[i][j]:表示当前 i {i} i 节点赋 j {j} j 值时,该子树的最小权值。
- 转移方程: d p [ u ] [ k ] + = ∑ d p [ j ] [ k ′ ] {dp[u][k] += \sum{dp[j][k^{'}]}} dp[u][k]+=∑dp[j][k′]
- u 是当前节点, k 是 u 节点赋的值。 { u是当前节点,k是u节点赋的值。} u是当前节点,k是u节点赋的值。
- j 是 u 的孩子, k ′ 是 j 节点不同于 k 值的值 {j是u的孩子,k'是j节点不同于k值的值} j是u的孩子,k′是j节点不同于k值的值
代码
int h[N], e[M], ne[M], idx;
int dp[N][5];
int ans = 2e17;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int f) {
for (int i = 1; i <= 4; i++) dp[u][i] = i;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == f) continue;
dfs(j, u);
for (int k = 1; k <= 4; k++) {
int s = 2e17;
for (int p = 1; p <= 4; p++)
if(k != p) s = min(s, dp[j][p]);
dp[u][k] += s;
}
}
}
// https://www.luogu.com.cn/problem/P4395
void solve() {
int n; cin >> n;
memset(h, -1, sizeof h);
for (int i = 0; i < n - 1; i++) {
int a, b; cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1, 0);
for (int i = 1; i <= 4; i++) {
ans = min(ans, dp[1][i]);
}
cout << ans << endl;
}