P2899 [USACO08JAN]手机网络Cell Phone Network

题意:

一棵 n 个点的无权树,求最?点覆盖

 

思路:

那么,我们考虑一个结点可以被谁染色,不难想出,可以有3种情况:被自己染色,被儿子染色,被父亲染色

我们不妨设:

f[i][0] 代表被自己染色      f[i][1] 代表被父亲染色       f[i][2] 代表被儿子染色

设当前节点是 u ,儿子节点是 v

我们来考虑下转移方程:

1自己被自己染色

这时我们可以想一下,u被自己染色可以由什么转移过来,如果u已经被自己染色了的话,他的儿子v可以选择自己染色,也可以选择被自己的儿子染色,当然也可以被u染色,当然,我们要选最小的,所以转移方程就是

f[u][0] += min(f[v][0],f[v][1],f[v][2] )

 

2被自己的父亲结点染色

如果被父亲结点(fa)染色了,那么u的儿子v只能选择自己染色或者被它的儿子染色,转移方程为

f[u][1] += min(f[v][1],f[v][0] )

 

 

3被自己的儿子结点染色

这是最麻烦的一种情况,因为u可能有多个儿子,只要有一个儿子自己染色了,就可以将u覆盖,这种情况就成立了

而现在它的儿子有两种情况,分别是自己染色和被它儿子染色

我们可以先假设每个儿子都是被它自己染色(v被自己染色)的,然后看一下u的每个儿子(v)被其儿子染色是否使结果变得更小,把能让结果更小的 自己染色(v自己染色)的儿子 替换为 被其儿子染色的儿子(v被它儿子染色)的儿子

 

技术图片

 

 

#include <iostream>#include <algorithm>#include <string>#include <string.h>#include <vector>#include <map>#include <stack>#include <set>#include <queue>#include <math.h>#include <cstdio>#include <iomanip>#include <time.h>#include <bitset>#include <cmath>#define LL long long#define INF 0x3f3f3f3f#define ls nod<<1#define rs (nod<<1)+1const double eps = 1e-10;const int maxn = 1e5 + 10;const LL mod = 1e9 + 7;int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}using namespace std;struct edge { int v,nxt;}e[maxn << 1];int head[maxn];int cnt;int f[maxn][3];inline void add_edge(int u,int v) { e[++cnt].v = v; e[cnt].nxt = head[u]; head[u] = cnt;}void dfs(int u,int fa) { f[u][0] = 1; int tot = 0; int g[maxn]; for (int i = head[u];~i;i = e[i].nxt) { int v = e[i].v; if (v == fa) continue; dfs(v,u); f[u][0] += min(f[v][0],min(f[v][1],f[v][2])); f[u][1] += min(f[v][0],f[v][2]); f[u][2] += f[v][0]; g[++tot] = f[v][2] - f[v][0]; } if (!tot) f[u][2] = INF; else { sort(g+1,g+1+tot); for (int i = 1;i < tot;i++) { if (g[i] < 0) f[u][2] += g[i]; else break; } }}int main() { cnt = 0; memset(head,-1, sizeof(head)); int n; cin >> n; for (int i = 1;i < n;i++) { int u,v; cin >> u >> v; add_edge(u,v); add_edge(v,u); } dfs(1,0); cout << min(f[1][0],f[1][2]) << endl; return 0;}

 

 

相关文章