【树形DP】BZOJ1596-[Usaco2008 Jan]电话网络
【题目大意】
在一棵有n个节点的树上建信号塔,每个节点的信号塔可以覆盖当前节点极其相连的节点。问要覆盖所有节点,至少需要多少座信号塔?
【思路】
经典的树形DP,直接复制一下。
f[i][0]:以i为根的子树中所有点均被覆盖且草地i上无信号塔所需的最小塔数(i被其儿子覆盖)
f[i][1]:以i为根的子树中所有点均被覆盖且草地i上有信号塔所需的最小塔数
f[i][2]:以i为根的子树中除i点以外其余点均被覆盖所需的最小塔数
f[i][0]=至少有一个儿子有塔的最小情况。所以这样处理:每次取f[j][0]和f[j][1]中较小的,如果有一个满足f[j][1]<f[j][0],OK。如果对于所有的儿子,f[j][0]较小,存下min(f[j][1]-f[j][0]),最后再加上就好了。
f[i][1]=∑min(f[j][0],f[j][1],f[j][2])
f[i][2]=∑min(f[j][0])
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=10000+50; 4 const int INF=0x7fffffff; 5 int n,f[MAXN][3]; 6 vector<int> E[MAXN]; 7 8 void init() 9 { 10 scanf("%d",&n); 11 for (int i=0;i<n-1;i++) 12 { 13 int a,b; 14 scanf("%d%d",&a,&b); 15 E[a].push_back(b); 16 E[b].push_back(a); 17 } 18 } 19 20 void dp(int fr,int u) 21 { 22 f[u][0]=f[u][2]=0; 23 f[u][1]=1; 24 int delta=INF,flag=0; 25 for (int i=0;i<E[u].size();i++) 26 { 27 int v=E[u][i]; 28 if (v==fr) continue; 29 dp(u,v); 30 if (f[v][1]<f[v][0]) flag=1;else delta=min(delta,f[v][1]-f[v][0]); 31 f[u][0]+=min(f[v][0],f[v][1]); 32 f[u][1]+=min(f[v][0],min(f[v][1],f[v][2])); 33 f[u][2]+=f[v][0]; 34 } 35 if (flag==0) f[u][0]+=delta; 36 if (E[u].size()==1 && E[u][0]==fr) 37 { 38 f[u][0]=n; 39 f[u][1]=1; 40 f[u][2]=0; 41 } 42 } 43 44 void printans() 45 { 46 printf("%d",min(f[1][0],f[1][1])); 47 } 48 49 int main() 50 { 51 init(); 52 dp(0,1); 53 printans(); 54 return 0; 55 }