首页 > 代码库 > 【树形DP】BZOJ1596-[Usaco2008 Jan]电话网络

【树形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 }

 

【树形DP】BZOJ1596-[Usaco2008 Jan]电话网络