最近在做些树形DP练练手

原题链接

大意就是给你一棵树,你可以断开任意数量的边,使得剩下的联通块大小乘积最大。

样例

8

1 2

1 3

2 4

2 5

3 6

3 7

6 8

输出

18

我首先想的是设\(f[i]\)表示以\(i\)为根的子树可获得的最大收益,但是会发现这样无法转移。考虑再加一维,\(f[i][j]\)表示以\(i\)的子树中,\(i\)所在的联通块大小为\(j\)的最大价值。然后我就傻了,想了半天也没想起来怎么转移,最后只好看了一眼题解。其实转移好简单的,貌似是个树上背包?考虑在\(dfs\)的过程中进行\(DP\),每当访问完一个点\(i\)的子结点时,累加一下\(sz[i]\),就枚举\(j\),并且用当前子结点的\(DP\)值来更新\(f[i][j]\)。转移方程大概会长成下面这个样子:

$f[i][j]=max(f[i][j],f[i][k]*f[v][j-k])$
(理解的话,就是把之前的大小为$k$的联通块和在当前子树中大小为$j-k$的联通块拼起来)
同时,我们特别定义$f[i][0]$表示以$i$为根的子树可获得的价值,则他的转移方程比较特殊:
$f[i][0]=max(f[i][0],f[i][j]*j)$
如果到这里这道题就结束的话,代码会长成下面这样:
```cpp
#include

using namespace std;

define N 700

define ll long long

int n, eid, sz[N+5], head[N+5];

ll f[N+5][N+5];

struct Edge {

int next, to;

}e[2*N+5];

void addEdge(int u, int v) {

e[++eid].next = head[u];

e[eid].to = v;

head[u] = eid;

}

void dp(int u, int fa) {

sz[u] = 1, f[u][0] = f[u][1] = 1;

for(int i = head[u]; i; i = e[i].next) {

int v = e[i].to;

if(v == fa) continue;

dp(v, u);

sz[u] += sz[v];

for(int j = sz[u]; j >= 1; --j) { //枚举i所在的联通块大小

for(int k = min(j, sz[u]-sz[v]); k >= max(1, j-sz[v]); --k) { //枚举子树根结点所在联通块大小

f[u][j] = max(f[u][j], f[u][k]f[v][j-k]);

}

}

}

for(int i = 1; i <= sz[u]; ++i) f[u][0] = max(f[u][0], f[u][i]
i);

}

int main() {

cin >> n;

for(int i = 1, x, y; i <= n-1; ++i) cin >> x >> y, addEdge(x, y), addEdge(y, x);

dp(1, 0);

cout << f[1][0] << endl;

return 0;

}

  1. 但是一交上去只有30$pts$,一看讨论区,发现还要用高精度!于是粘了个板子上去,然后就开心的$MLE$了 ̄▽ ̄。最后把$int$换成$short$就对了,无语。
  2. 粘一下$AC$代码
  3. ```cpp
  4. #include <cstdio>
  5. #include <iostream>
  6. #include <cstring>
  7. using namespace std;
  8. #define N 700
  9. int n, eid;
  10. short sz[N+5], head[N+5];
  11. struct Edge {
  12. int next, to;
  13. }e[2*N+5];
  14. struct bign{ //高精类模板,网上找的
  15. static const int maxn = 120;
  16. short d[maxn+5];
  17. short len;
  18. void clean() { while(len > 1 && !d[len-1]) len--; }
  19. bign() { memset(d, 0, sizeof(d)); len = 1; }
  20. bign(int num) { *this = num; }
  21. bign(char* num) { *this = num; }
  22. bign operator = (const char* num) {
  23. memset(d, 0, sizeof(d)); len = strlen(num);
  24. for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0';
  25. clean();
  26. return *this;
  27. }
  28. bign operator = (int num){
  29. char s[20]; sprintf(s, "%d", num);
  30. *this = s;
  31. return *this;
  32. }
  33. bign operator + (const bign& b) {
  34. bign c = *this; int i;
  35. for(i = 0; i < b.len; i++) {
  36. c.d[i] += b.d[i];
  37. if (c.d[i] > 9) c.d[i] %= 10, c.d[i+1]++;
  38. }
  39. while (c.d[i] > 9) c.d[i++] %= 10, c.d[i]++;
  40. c.len = max(len, b.len);
  41. if (c.d[i] && c.len <= i) c.len = i+1;
  42. return c;
  43. }
  44. bign operator - (const bign& b) {
  45. bign c = *this; int i;
  46. for(i = 0; i < b.len; i++) {
  47. c.d[i] -= b.d[i];
  48. if (c.d[i] < 0) c.d[i] += 10, c.d[i+1]--;
  49. }
  50. while (c.d[i] < 0) c.d[i++] += 10, c.d[i]--;
  51. c.clean();
  52. return c;
  53. }
  54. bign operator * (const bign& b) const {
  55. int i, j; bign c; c.len = len + b.len;
  56. for(j = 0; j < b.len; j++)
  57. for(i = 0; i < len; i++)
  58. c.d[i+j] += d[i]*b.d[j];
  59. for(i = 0; i < c.len-1; i++) c.d[i+1] += c.d[i]/10, c.d[i] %= 10;
  60. c.clean();
  61. return c;
  62. }
  63. bign operator / (const bign& b) {
  64. int i, j;
  65. bign c = *this, a = 0;
  66. for(i = len - 1; i >= 0; i--) {
  67. a = a*10 + d[i];
  68. for (j = 0; j < 10; j++)
  69. if (a < b*(j+1)) break;
  70. c.d[i] = j;
  71. a = a - b*j;
  72. }
  73. c.clean();
  74. return c;
  75. }
  76. bign operator % (const bign& b) {
  77. int i, j;
  78. bign a = 0;
  79. for(i = len - 1; i >= 0; i--) {
  80. a = a*10+d[i];
  81. for(j = 0; j < 10; j++) if (a < b*(j+1)) break;
  82. a = a-b*j;
  83. }
  84. return a;
  85. }
  86. bign operator += (const bign& b) {
  87. *this = *this+b;
  88. return *this;
  89. }
  90. bool operator <(const bign& b) const {
  91. if(len != b.len) return len < b.len;
  92. for(int i = len-1; i >= 0; i--)
  93. if(d[i] != b.d[i]) return d[i] < b.d[i];
  94. return false;
  95. }
  96. bool operator >(const bign& b) const { return b < *this; }
  97. bool operator <= (const bign& b) const { return !(b < *this); }
  98. bool operator >= (const bign& b) const { return !(*this < b); }
  99. bool operator != (const bign& b) const { return b < *this || *this < b; }
  100. bool operator == (const bign& b) const { return !(b < *this) && !(b > *this); }
  101. string str() const {
  102. char s[maxn] = {};
  103. for(int i = 0; i < len; i++) s[len-1-i] = d[i]+'0';
  104. return s;
  105. }
  106. }f[N+5][N+5];
  107. istream& operator >> (istream& in, bign& x) {
  108. string s;
  109. in >> s;
  110. x = s.c_str();
  111. return in;
  112. }
  113. ostream& operator << (ostream& out, const bign& x) {
  114. out << x.str();
  115. return out;
  116. }
  117. void addEdge(int u, int v) {
  118. e[++eid].next = head[u];
  119. e[eid].to = v;
  120. head[u] = eid;
  121. }
  122. void dp(int u, int fa) {
  123. sz[u] = 1, f[u][0] = f[u][1] = 1;
  124. for(int i = head[u]; i; i = e[i].next) {
  125. int v = e[i].to;
  126. if(v == fa) continue;
  127. dp(v, u);
  128. sz[u] += sz[v];
  129. for(int j = sz[u]; j >= 1; --j) {
  130. for(int k = min(j, sz[u]-sz[v]); k >= max(1, j-sz[v]); --k) {
  131. f[u][j] = max(f[u][j], f[u][k]*f[v][j-k]);
  132. }
  133. }
  134. }
  135. for(int i = 1; i <= sz[u]; ++i) f[u][0] = max(f[u][0], f[u][i]*i);
  136. }
  137. int main() {
  138. cin >> n;
  139. for(int i = 1, x, y; i <= n-1; ++i) cin >> x >> y, addEdge(x, y), addEdge(y, x);
  140. dp(1, 0);
  141. cout << f[1][0] << endl;
  142. return 0;
  143. }

洛谷 P1411 树的更多相关文章

  1. 洛谷 P1411 树 (树形dp)

    大意: 给定树, 求删除一些边, 使得连通块大小的乘积最大 设$dp_{i,j}$表示只考虑点$i$的子树, $i$所在连通块大小为$j$的最大值. 转移的时候不计算$i$所在连通块的贡献, 留到最后 ...

  2. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  3. 洛谷P3384 树链剖分

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...

  4. 洛谷 P3384 树链剖分(模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  5. 洛谷P1268 树的重量

    P1268 树的重量 85通过 141提交 题目提供者该用户不存在 标签树形结构 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 有这种情况吗!!!! 题意似乎有问题 题目描述 树可以用来表 ...

  6. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  7. 【树链剖分】洛谷P3384树剖模板

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  8. 洛谷P3248 树 [HNOI2016] 主席树+倍增+分治

    正解:主席树+倍增+分治 解题报告: 传送门! 首先看到这题会想到之前考过的这题 但是那题其实简单一些,,,因为那题只要用个分治+预处理就好,只是有点儿思维难度而已 这题就不一样,因为它说了是按照原树 ...

  9. 洛谷P3368 树状数组2 树状数组+差分

    正解:树状数组+差分 解题报告: 戳我! 不得不说灵巧真滴是越来越弱了...连模板题都要放上来了QAQ 因为今天考试的T3正解要用到树状数组这才惊觉树状数组掌握得太太太太差了...之前一直靠线段树续着 ...

随机推荐

  1. SQL Server 数据库部分常用语句小结(二)

    9. 查询备份还原数据库的进度. select command ,percent_complete ,est_time_to_go=convert(varchar,(estimated_complet ...

  2. 【公众号系列】两分钟学会SAP F1技巧

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[公众号系列]两分钟学会SAP F1技巧   写 ...

  3. linux 网络套接字

    在内核分析网络分组时,底层协议的数据将传输到跟高的层.而发送数据的时候顺序是相反的.每一层都是通过加(首部+净荷)传向跟底层,直至最终发送. 这些操作决定了网络的的性能. 就如下图所示 linux因此 ...

  4. Cs231n课堂内容记录-Lecture 8 深度学习框架

    Lecture 8  Deep Learning Software 课堂笔记参见:https://blog.csdn.net/u012554092/article/details/78159316 今 ...

  5. Sublime3如何用快捷键实现字母的大小写转换

    说明 有的时候需要将字母大小写一键转换一下,很显然,通过编辑器来实现会更加轻量级,而不是打开IDE去实现 我用的Sublime3版本如下: 步骤 1.打开Sublime的Key Bindings 2. ...

  6. apache https配置【转】

    博文来源:apache https配置 参考博文:apache.nginx配置自签名证书 1.  确认是否安装ssl模块 是否有mod_ssl.so文件 2.  生成证书和密钥 linux下 步骤1: ...

  7. SQL解析在美团的应用

    https://tech.meituan.com/SQL_parser_used_in_mtdp.html 数据库作为核心的基础组件,是需要重点保护的对象.任何一个线上的不慎操作,都有可能给数据库带来 ...

  8. MongoDB install

    下载地址1:https://www.mongodb.org/dl/linux下载地址2:https://www.mongodb.com/download-center/community关于Mongo ...

  9. Mongo字符串类型的数值查询---$Where查询介绍

    ​        在Mongo中都知道字符串类型大小比较都是以ASCII进行比较的,所以无法真实比较字符串类型的数值大小 ​      比如查询age大于3的: db.getCollection(&q ...

  10. 第十一节,利用yolov3训练自己的数据集

    1.环境配置 tensorflow1.12.0 Opencv3.4.2 keras pycharm 2.配置yolov3 下载yolov3代码:https://github.com/qqwweee/k ...