题解 P2899 【[USACO08JAN]手机网络Cell Phone Network】
题意
1. 自己被自己染色
这时我们可以想一下,
2. 被自己的父亲结点染色
如果被父亲结点(
3. 被自己的儿子结点染色
这是最麻烦的一种情况,因为
而现在它的儿子有两种情况,分别是自己染色和被它儿子染色
我们可以先假设每个儿子都是被它自己染色(
(参考了
那么怎么实现呢?
- 先让
f[u][1] 加上所有的f[v][0] (也就是假设所有的v 目前都是自己给自己染色的) - 在进行一的同时,用一个
g 数组,表示v 被儿子染色所需的价值减去v 被自己染色的价值的差值,同时用一个变量tot 记录一下一共有多少个儿子,即g[++tot] = f[v][1] - f[v][0] - 如果
u 没有儿子,即tot 为0 ,说明u 是一个叶结点,那么就没有从儿子来的价值,因为转移的时候我们要取小的,所以就把f[u][1] 设为一个极大值 - 如果
u 有儿子,就将g 从小到大排序,如果是负值,我们就可以替换,因为是负值的话就说明,此时的f[v][1] 比f[v][0] 小,所以就可以替换,只要是负的,值越小越好,所以就排序一下,是负的就替换,否则就break ,当然我们最多替换tot-1 个,因为要保证u 被染色,必须有一个儿子是自己染色的
至此主要部分就讲完了,需要注意的是每次
然后我们就做完啦~~
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int M = 1e5 + 11;
const int INF = 1e9 + 17;
int n, m;
int f[M][3];//f[i][0/1/2]0表示被自己染了,1表示被儿子染了,2表示被父亲染了
struct node {
int nxt, to;
} e[M];
int head[M], cnt;
inline void add(int from, int to) {
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
bool cmp(int x, int y) {
return x > y;
}
void dfs(int u, int fa) {
int tot = 0, g[M]; f[u][0] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fa) continue;
dfs(v, u);
f[u][0] += min(f[v][0], min(f[v][1], f[v][2]));
f[u][2] += min(f[v][0], f[v][1]);
f[u][1] += f[v][0];
g[++tot] = f[v][1] - f[v][0];
}
if(!tot) f[u][1] = INF;
else {
sort(g + 1, g + 1 + tot);
for(int i = 1; i < tot; i++) {
if(g[i] < 0) f[u][1] += g[i];
else break;
}
}
return;
}
int main() {
n = read();
for(int i = 1; i < n; i++) {
int x = read(), y = read();
add(x, y), add(y, x);
}
dfs(1, 0);
printf("%d", min(f[1][0], f[1][1]));
return 0;
}
完结撒花qwq