您的位置:首页 > 其它

poj 3659 Cell Phone Network USACO 树形DP

2016-06-14 17:29 393 查看
传送门

题目大意:

给出一颗n个节点的树(也就是有n-1条边),请选出最小点数使得所有点被覆盖掉(每个节点可以被自己覆盖,也可以被父亲覆盖,还可以被儿子覆盖)

分析:

好难啊( ⊙ o ⊙ )啊!

f[i][0]代表选择i节点,那么i和i的儿子都被覆盖

f[i][1]代表不选i节点,但是i被儿子覆盖

f[i][2]代表不选i节点,并且i不被儿子覆盖,但是儿子已经被覆盖

f[i][0]+=min(f[to[i]][0],f[to[i]][1],f[to[i]][2])

f[i][2]+=min(f[to[i]][0],f[to[i]][1])

这两个很容易理解

那么f[i][1]怎么转移呢(⊙o⊙)?

我们要保证至少有一个儿子是选择的

所以我们选择k点

f[i][1]=f[k][0]+sum((f[to[i]!=k][1],f[to[i]!=k][0]))

然后O(n)的枚举k点即可O(∩_∩)O哈!

代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 0x3f3f3f3f
#define MIN(a,b,c) min(a,min(b,c))
using namespace std;
const int maxn=10000+5;
int n,hd[maxn],to[maxn*2],nxt[maxn*2],cnt,f[maxn][3];
void add(int x,int y){
to[cnt]=y;
nxt[cnt]=hd[x];
hd[x]=cnt++;
}
void dfs(int root,int fa){
int sum=0;
f[root][0]=1;//root is chosen and root&root's son are covered
f[root][1]=inf;//root is not chosen and root&root's son are covered
f[root][2]=0;//root is not chosen and root si not covered ,root's son is covered
for(int i=hd[root];i!=-1;i=nxt[i]){
if(to[i]==fa)
continue;
dfs(to[i],root),sum+=min(f[to[i]][1],f[to[i]][0]);
f[root][0]+=MIN(f[to[i]][0],f[to[i]][1],f[to[i]][2]);
f[root][2]+=min(f[to[i]][0],f[to[i]][1]);
}
for(int i=hd[root];i!=-1;i=nxt[i]){
if(to[i]==fa)
continue;
f[root][1]=min(f[root][1],f[to[i]][0]+sum-min(f[to[i]][0],f[to[i]][1]));
}
}
signed main(void){
memset(hd,-1,sizeof(hd));
scanf("%d",&n),cnt=0;
for(int i=1,x,y;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
memset(f,inf,sizeof(f));
dfs(1,-1);
cout<<min(f[1][0],f[1][1])<<endl;
return 0;
}


by >o< neighthorn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: