https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5015

设dp[cur][i][j]表示当前是第cur个顶点,自身状态是i(0或者1),爸爸的状态是j(0或者1)的时候的最多白色节点数。

0---白色

1---黑色

如果不合法,就是第cur号顶点不能染成白色,则为-1,注意到任意节点都可以染成黑色,所以dp[cur][1][0] = dp[cur][1][1] = 0

转移:

首先把叶子节点特判掉,因为叶子节点的状态很容易判断,并且只有k == 1的时候,才有dp[left][0][1] = 1

然后留给每一个爸爸的转移就是:

1、如果爸爸染黑色,则从  dp[son][1][1]和dp[son][0][1]娶个max过来即可。

2、比较麻烦的是爸爸染了白色。这样就相当于对于所有的儿子(儿子的状态已经全部算出来了),把k个染成黑色(使得爸爸合法),剩下的染成白色,使得白色节点数最大,

也就是给出一个结构体数组,有arr[i].a和arr[i].b表示这个节点染成白色,得到arr[i].a贡献,这个节点染成黑色,得到arr[i].b贡献。

设d[n][k]表示前n个物品,确定选了k个做黑色的最大贡献。二维费用背包转移即可。hack: 需要用到d[i][0]

所以d[0][0] = 0,而d[1][0] = arr[1].a    d[2][0] = arr[1].a + arr[2].a

这题写那个二维费用dp的时候坑队友了,没写出来,转移的时候没考虑d[i][0]

  1. #include <bits/stdc++.h>
  2. #include <algorithm>
  3. #define inf (0x3f3f3f3f)
  4. using namespace std;
  5. typedef long long int LL;
  6. const int maxn = 1e2 + ;
  7. int dp[maxn][][];
  8. char str[ + ];
  9. struct Edge {
  10. int u, v, tonext;
  11. } e[maxn * ];
  12. int first[maxn], num;
  13. void addEdge(int u, int v) {
  14. e[num].u = u, e[num].v = v, e[num].tonext = first[u];
  15. first[u] = num++;
  16. }
  17. int son[maxn];
  18. bool in[maxn];
  19. int n, k;
  20.  
  21. void show() {
  22. for (int i = ; i <= n; ++i) {
  23. printf("node %d: ", i);
  24. for (int j = first[i]; ~j; j = e[j].tonext) {
  25. printf("%d ", e[j].v);
  26. }
  27. printf("\n");
  28. }
  29. printf("***************\n");
  30. }
  31. vector<int> vc[maxn];
  32. int d[maxn][];
  33. struct Node {
  34. int a, b;
  35. Node(int _a, int _b) {
  36. a = _a, b = _b;
  37. }
  38. Node() {}
  39. } arr[maxn];
  40. int getMax(struct Node arr[], int n, int k) {
  41. if (k < ) return -inf;
  42. if (k == ) {
  43. int sum = ;
  44. for (int i = ; i <= n; ++i) sum += arr[i].a;
  45. return sum;
  46. }
  47. if (n < k) return -inf;
  48. memset(d, -0x3f, sizeof d);
  49. d[][] = ;
  50. for (int i = ; i <= n; ++i) {
  51. for (int j = k; j >= ; --j) {
  52. if (d[i - ][j] >= ) d[i][j] = max(d[i][j], d[i - ][j] + arr[i].a);
  53. if (j >= && d[i - ][j - ] >= ) d[i][j] = max(d[i][j], d[i - ][j - ] + arr[i].b);
  54. }
  55. }
  56. return d[n][k];
  57. }
  58. void dfs(int cur) {
  59. if (!son[cur]) return;
  60. for (int i = first[cur]; ~i; i = e[i].tonext) {
  61. int v = e[i].v;
  62. vc[cur].push_back(v);
  63. dfs(v);
  64. dp[cur][][] += max(dp[v][][], dp[v][][]);
  65. dp[cur][][] += max(dp[v][][], dp[v][][]); // 爸爸是黑色
  66. }
  67. int sel = , val = , to = ;
  68. for (int i = ; i < vc[cur].size(); ++i) {
  69. int v = vc[cur][i];
  70. if (dp[v][][] >= ) {
  71. arr[++to] = Node(dp[v][][], dp[v][][]);
  72. } else {
  73. sel++; //这些不能变成白色,也就是固定必须是黑色
  74. val += dp[v][][]; //其贡献
  75. }
  76. }
  77. dp[cur][][] = getMax(arr, to, k - - sel) + val;
  78. dp[cur][][] = getMax(arr, to, k - sel) + val;
  79. if (dp[cur][][] < ) dp[cur][][] = -;
  80. else dp[cur][][]++;
  81. if (dp[cur][][] < ) dp[cur][][] = -;
  82. else dp[cur][][]++;
  83. }
  84. void work() {
  85. num = ;
  86. memset(in ,false, sizeof in);
  87. memset(first, -, sizeof first);
  88. memset(dp, -, sizeof dp);
  89. memset(son, false, sizeof son);
  90. scanf("%d%d", &n, &k);
  91. for (int i = ; i <= maxn - ; ++i) vc[i].clear();
  92. getchar();
  93. for (int i = ; i <= n; ++i) {
  94. gets(str + );
  95. // printf("%s\n", str + 1);
  96. int lenstr = strlen(str + );
  97. for (int j = ; j <= lenstr;) {
  98. if (str[j] >= '' && str[j] <= '') {
  99. int fuck = str[j] - '';
  100. ++j;
  101. while (j <= lenstr && str[j] >= '' && str[j] <= '') {
  102. fuck = fuck * + str[j] - '';
  103. ++j;
  104. }
  105. if (fuck == ) break;
  106. son[i]++;
  107. addEdge(i, fuck);
  108. in[fuck] = true;
  109. } else j++;
  110. }
  111. }
  112. int root = ;
  113. for (int i = ; i <= n; ++i) {
  114. if (!in[i]) {
  115. root = i;
  116. break;
  117. }
  118. }
  119. // show();
  120. if (n == ) {
  121. if (k != ) {
  122. printf("0\n");
  123. return;
  124. }
  125. }
  126. for (int i = ; i <= n; ++i) {
  127. dp[i][][] = dp[i][][] = ;
  128. }
  129. if (k == ) {
  130. printf("%d\n", n);
  131. return;
  132. }
  133. if (k == ) {
  134. for (int i = ; i <= n; ++i) {
  135. if (!son[i]) {
  136. dp[i][][] = ;
  137. dp[i][][] = -;
  138. dp[i][][] = ;
  139. dp[i][][] = ;
  140. }
  141. }
  142. }
  143. dfs(root);
  144. int ans = dp[root][][];
  145. ans = max(ans, dp[root][][]);
  146. ans = max(ans, dp[root][][]);
  147. // ans = max(ans, dp[root][0][1]);
  148. printf("%d\n", ans);
  149. }
  150.  
  151. int main() {
  152. #ifdef local
  153. freopen("data.txt", "r", stdin);
  154. #endif
  155. int t;
  156. scanf("%d", &t);
  157. while (t--) work();
  158. return ;
  159. }

Regionals 2014 >> Asia - Taichung 7003 - A Balance Game on Trees 树形DP + 二维费用背包的更多相关文章

  1. 2014 Super Training #9 E Destroy --树的直径+树形DP

    原题: ZOJ 3684 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684 题意: 给你一棵树,树的根是树的中心(到其 ...

  2. [The Preliminary Contest for ICPC Asia Nanjing 2019] A-The beautiful values of the palace(二维偏序+思维)

    >传送门< 前言 这题比赛的时候觉得能做,硬是怼了一个半小时,最后还是放弃了.开始想到用二维前缀和,结果$n\leq 10^{6}$时间和空间上都爆了,没有办法.赛后看题解用树状数组,一看 ...

  3. The Preliminary Contest for ICPC Asia Xuzhou 2019 J Random Access Iterator (树形DP)

    每次循环向下寻找孩子时,随机选取一个孩子,设dp[u]为从u出发,不能得出正确答案的概率,则从u出发,走一次的情况下不能得出正确答案的概率是 P = (dp[v1]+dp[v2]+dp[v3]+--d ...

  4. The Preliminary Contest for ICPC Asia Shenyang 2019 D. Fish eating fruit(树形dp)

    题意:求一棵树上所有路径和模3分别为0 1 2 的权值的和 思路:树形dp 增加一个记录儿子节点满足条件的个数的数组 不要放在一起dp不然答案跟新会有问题 #include <bits/stdc ...

  5. 2015 UESTC Winter Training #4【Regionals 2008 :: Asia - Tehran】

    2015 UESTC Winter Training #4 Regionals 2008 :: Asia - Tehran 比赛开始时电脑死活也连不上WIFI,导致花了近1个小时才解决_(:зゝ∠)_ ...

  6. C++ 洛谷 2014 选课 from_树形DP

    洛谷 2014 选课 没学树形DP的,看一下. 首先要学会多叉树转二叉树. 树有很多种,二叉树是一种人人喜欢的数据结构,简单而且规则.但一般来说,树形动规的题目很少出现二叉树,因此将多叉树转成二叉树就 ...

  7. hdu5071 2014 Asia AnShan Regional Contest B Chat

    模拟题: add的时候出现过的则不再添加 close的时候会影响到top rotate(Prior.Choose)的时候会影响到top /*============================== ...

  8. UVALive 7138 The Matrix Revolutions(Matrix-Tree + 高斯消元)(2014 Asia Shanghai Regional Contest)

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...

  9. UVALive 7143 Room Assignment(组合数学+DP)(2014 Asia Shanghai Regional Contest)

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...

随机推荐

  1. BZOJ1218:[HNOI2003]激光炸弹

    我对状态空间的理解:https://www.cnblogs.com/AKMer/p/9622590.html 题目传送门:https://www.lydsy.com/JudgeOnline/probl ...

  2. bzoj 4066 & bzoj 2683 简单题 —— K-D树(含重构)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4066 https://www.lydsy.com/JudgeOnline/problem.p ...

  3. sys.argv用法

    argv是在脚本内部使用,旨在接受命令传参 比如,一个脚本argv.py,代码里面有,sys.argv[1],,sys.argv[2],那么运行这个脚本时,必须在后面跟两个参数,用空格隔开,如:pyt ...

  4. asp.net分页asp.net无刷新分页高效率分页

    项目中经常会用到分页的功能类似的项目做过无数个了,今个把自己常用的分页代码分享一下. 首先说说服务端处理的代码: 下面代码中重点是分页的sql语句的写法,其中的参数@n是当前的页码,总的来说本服务端主 ...

  5. Poj 1887 Testing the CATCHER(LIS)

    一.Description A military contractor for the Department of Defense has just completed a series of pre ...

  6. Ruby中的并行赋值和嵌套赋值

    一. Ruby 的赋值实际是以并行方式执行的,所以赋值语句右边的值不受赋值语句本身的影响.在左边的任意一个变量或属性赋值之前,右边的值按他们出现的顺序被计算出来. 1.当赋值语句有多于一个左值时,赋值 ...

  7. linux日常管理-rsync_ssh方式

    现在我们有两台机器,两台机器都需要安装rsync    yum -y install rsync       一台的主机名是wangshaojun IP是192.168.1.117 ,另一台的主机名是 ...

  8. 将gridview 的数据导出EXCEL

    gridview数据 单击“导出EXCEL”按钮后        1.在上面的代码中,先将gridview绑定到指定的数据源中,然后在button按钮(用来做导出到EXCEL的)的事件中,写入相关的代 ...

  9. javaScript笔记01

    所谓勇气就是明知前方的路途充满了荆棘险阻,但还是义无反顾的的走下去. 1 Javasrcipt定义的三种方式 ·1 head中的script脚本 <!DOCTYPE html> <h ...

  10. [poj3259]Wormholes(spfa判负环)

    题意:有向图判负环. 解题关键:spfa算法+hash判负圈. spfa判断负环:若一个点入队次数大于节点数,则存在负环.  两点间如果有最短路,那么每个结点最多经过一次,这条路不超过$n-1$条边. ...