[CQOI2005]珠宝
本题传送门
题目大意
给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数。
唯一的限制条件是相临的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小。
解题思路
本题相当于一个染色问题。
本蒟蒻开始以为是 (危
其实可以有一组 Hack 数据。
数据1
将数据构造成一棵树:
如果是
如图可知,总价值为
再根据图进行分析,可以发现,对总价值贡献最多的是节点
那能不能修改通过修改图的一个节点,使得这
答案是,可以。
怎么做?
将节点
则正确的染色方法为:
再来一组数据。 (还有完没完
数据2
根据两种情况:
- 一个节点的权值只受到他的父节点和子节点的影响。
- 这是一棵树,一定存在 dfs 序。
可以想到这道题正解其实是 树形dp。
定义
现在要找一个最大可以填的数,为
我们可以出于最坏的情况来进行考虑,当周围的点呈现出
为了不 WA ,
所以转移方程为:
AC CODE
#include <bits/stdc++.h>
using namespace std;
const int _ = 2e5 + 5;
int n, f[_][5], ans = INT_MAX;
int tot, head[_], to[_], nxt[_];
void add(int a, int b)
{
nxt[++tot] = head[a];
head[a] = tot;
to[tot] = b;
}
void dfs(int x, int fa)
{
for (int i = 1; i <= 4; i++)
f[x][i] = i;
for (int i = head[x]; i; i = nxt[i])
{
int v = to[i];
if (v == fa)
continue;
dfs(v, x);
for (int j = 1; j <= 4; j++)
{
int minn = INT_MAX;
for (int k = 1; k <= 4; k++)
if (j != k)
minn = min(minn, f[v][k]);
f[x][j] += minn;
}
}
}
signed main()
{
scanf("%d", &n);
for (int i = 1, a, b; i < n; ++i)
{
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1, 0);
for (int i = 1; i <= 4; i++)
ans = min(ans, f[1][i]);
printf("%d", ans);
return 0;
}