codeforce 382 div2 E —— 树状dp

题意:给一棵n个结点的无根树染色,求使每个结点距离为k的范围内至少有一个被染色的结点的总染色方法数目

分析:首先我们定义: 对于结点v, 如果存在一个黑色结点u距离v不超过k,则结点v被“控制”

   首先将无根树转换成以1为根的有根树,设dp[v][i]为对于以v为根的子树,距离v最近的黑色结点深度为i时, 该子树中结点全部被控制或者可能在其他子树的影响下被全部控制的染色方法数。

   下面来解释一下, 我们知道,当两个黑色结点距离不超过2*k+1时,其间的所有节点都被控制。那么当 i <= k 时,子树中的结点可以被全部控制, 当 k + 1 <= i <= 2*k+1 时, 子树中的节点不可能自动全被控制,但是可能在该子树根结点染色以及其他子树影响下被全部控制。

   如何计算v的dp值呢,假如v只有一个儿子u, 那么 dp[v][i] = dp[u][i-1]; 如果v有多个儿子,那么首先按上述方法合并v和第一个子树,然后将子树v与其他子树合并。

   那么如何合并两棵子树v, u呢?

   首先考虑v的根结点为白色的状态,可以枚举(i,j)的所有情况,其中 i 是第一棵子树最近黑结点的深度(i>0),j 是第二棵子树最近黑结点的深度,如果i+j <= 2*k,则更新dp[v][min(i, j+1)], 这个状态是节点全部被控制的状态。如果i+j > 2*k, 则此状态子树中节点无法自发地全部被控制,但是可以在其他子树的影响下被全部控制。

   if  i+j <= 2*k , update dp[v][min(i, j+1)]

   else update dp[v][max(i,  j+1)]

   计算完根结点为白色的情况之后,考虑根结点为黑色,那么最近距离v节点不超过2*k+1的情况数目之和就是所求,

                即 dp[v][0] = ∑ dp[v][i] ( i from 1 to 2*k+1 )

   比较难以理解的地方是一个子树全为白色的情况如何进行更新,其实可以这样想,对于每个叶子节点u,假想距离u节点k+1的深度有一个黑色结点,那么对于子树u,dp[u][0] = 1,这是子树完全被控制的情况, dp[u][k+1] = 1, 这是该叶子节点可能在其他子树影响下被控制的情况。这样对于所有节点都可以以上述方式更新。

ps:此题难点在于状态的设计以及状态的转移方法,需要反复琢磨。

附上代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <vector>
 5 #include <iostream>
 6
 7 using namespace std;
 8 typedef long long LL;
 9
10 #define M 1000000007
11 #define rep(i, x, n) for(int i = x; i <= (n); i++)
12 const int maxn = 104;
13 const int maxk = 20 + 3;
14
15 LL dp[maxn][2*maxk];
16 LL temp[2*maxk];
17
18 vector<int> G[maxn];
19 int n, k;
20 void dfs(int v, int f) {
21     int len = G[v].size();
22     if(G[v].size() == 1 && f != 0) { //处理除 1 这个根结点之外的叶子
23         dp[v][0] = dp[v][k+1] = 1;
24         return ;
25     }
26     int flag = 0;
27     rep(i, 0, len-1) {
28         int u = G[v][i];
29         if(u == f) continue;
30         dfs(u, v);
31         if(!flag) {
32             rep(i, 0, 2*k) dp[v][i+1] = dp[u][i];
33             flag = 1;
34         }
35         else {
36             rep(i, 0, 2*k+1) temp[i] = dp[v][i], dp[v][i] = 0;
37             rep(i, 0, 2*k) rep(j, 1, 2*k+1)
38                 if(i+j <= 2*k) dp[v][min(j, i+1)] = (dp[v][min(j, i+1)] + temp[j]*dp[u][i]) % M;
39                 else dp[v][max(j, i+1)] = (dp[v][max(j, i+1)] + temp[j]*dp[u][i]) % M;
40         }
41     }
42    //计算子树根结点为黑色的情况
43     rep(i, 1, 2*k+1) dp[v][0] = (dp[v][0] + dp[v][i]) % M;
44 }
45 int main(){
46     scanf("%d%d", &n, &k);
47     rep(i, 1, n) G[i].clear();
48     memset(dp, 0, sizeof dp);
49     for(int i = 1;i < n; i++){
50         int a, b;
51         scanf("%d%d",&a, &b);
52         G[a].push_back(b);
53         G[b].push_back(a);
54     }
55     dfs(1, 0);
56     LL ans = 0;
57     for(int i = 0;i <= k; i++)
58         ans = (ans + dp[1][i])%M;
59     if(!ans) ans = 1;
60     cout << ans << endl;
61     return 0;
62 }  
时间: 2024-10-14 02:43:39

codeforce 382 div2 E —— 树状dp的相关文章

POJ 1155 树状dp

TELE Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3856   Accepted: 2054 Description A TV-network plans to broadcast an important football match. Their network of transmitters and users can be represented as a tree. The root of the tre

洛谷P1122 最大子树和 (树状dp)

题目描述 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是当日课后,小明就向老师提出了这个问题: 一株奇怪的花卉,上面共连有N 朵花,共有N-1条枝干将花儿连在一起,并且未修剪时每朵花都不是孤立的.每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负 数的,说明这朵花看着都让人恶心.所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉

POJ 1463 树状dp

Strategic game Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 6629   Accepted: 3058 Description Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad

POJ 2342 树状dp

Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4606   Accepted: 2615 Description There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure

poj1947--Rebuilding Roads(树状dp)

Rebuilding Roads Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 9496   Accepted: 4316 Description The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The

洛谷P2015 二叉苹果树(树状dp)

题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树 2 5 \ / 3 4 \ / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 输入输出格式 输入格式: 第1行2个数,N和Q(1<=Q<= N,1<N<=100). N表示树

树状DP入门

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 题目大意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少? 解题思路:树形DP入门题.由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优.其实不然,有可能父节点和子节点都不选,而要选子孙节点.不过只要再往深点想下,就可以得出动态规划的解法.每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那

树状DP (poj 2342)

题目:Anniversary party 题意:给出N各节点的快乐指数,以及父子关系,求最大快乐指数和(没人职员愿意跟直接上司一起玩): 思路:从底向上的树状DP: 第一种情况:第i个员工不参与,F[i][0] += max(F[k][1], F[k][0]);(k为i的儿子) 第二种情况:第i个员工参与,F[i][1] += F[k][0]; F[i][j]表示第i个员工是否参与: 边界:F[i][0] = 0:F[i][1] = 其快乐指数: #include <iostream> #in

poj2486--Apple Tree(树状dp)

Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7789   Accepted: 2606 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amoun