Luogu-P2015 二叉苹果树
Posted endsah
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu-P2015 二叉苹果树相关的知识,希望对你有一定的参考价值。
题面传送门: Luogu-P2015
题目描述
给定一棵 (n) 个节点的以 (1) 为根的二叉树(严格二叉), 树边有边权. 现在需要剪去一些树边(剪边定义为: 若剪去一条边 ((u,v)), 在删除该边的同时也必须舍弃以 (v) 为根的整个子树), 问在留下 (m) 条边时边权之和的最大值.
(n le 100,m<n).
题目分析
非常明显的树形DP.
设 (F[u][j]) 表示以 (u) 为根的子树中留下 (j) 条边的最大权值, 答案即为 (F[1][m]).
1.状态转移方程:
[
F[u][j]=max{F[u][j-k-1]+F[v][k]+w_{u,v}}1 le j le min(m,size[u]),0 le k le min(j-1,size[v])
]
其中 (v) 是 (u) 的一个子节点, (w_{u,v}) 表示边 ((u,v)) 的权值, (size[i]) 表以 (i) 为根的子树中边的数量, (k) 是枚举出来的, 表示在以 (v) 为根的子树中选 (k) 条边.
2.解释:
- 若在子树 (v) 中选中了 (k) 条边, 那么在其他子树中只能选择 (k-j-1) 条边(因为当前这条边 ((u,v)) 必须选择, 不然不合法)
- (k) 的范围必须小于等于 (j-1) , 因为当 (k=j) 时, (j-k-1) 的值为 (-1), 显然不合法.
3.复杂度:
因每个点只会访问一次, 每次访问枚举需要 (n^2) 的复杂度, 故总复杂度为 (O(n^3)), 并且常数极小.
实现细节
- 记忆化搜索.
- (j,k) 需要倒序枚举, 原因同 (01) 背包.
- 记忆化搜索的同时处理 (size) 数组.
代码
/**********************************************************
* Author : EndSaH
* Email : [email protected]
* Created Time : 2018-11-17 09:36
* FileName : temp.cpp
* *******************************************************/
#include <cstdio>
#include <cctype>
#include <iostream>
namespace Fast_IO
{/*{{{*/
char ibuf[1 << 20], obuf[1 << 20], stk[20];
char *ipos = ibuf, *iend = ibuf, *opos = obuf, *oend = obuf + (1 << 20), *stkpos = stk;
inline char Getchar()
{
return ipos == iend and (iend = (ipos = ibuf) + fread(ibuf, 1, 1 << 20, stdin), ipos == iend) ? EOF : *ipos++;
}
inline void Putchar(char c)
{
if(opos == oend)
{
fwrite(obuf, 1, 1 << 20, stdout);
opos = obuf;
}
*opos++ = c;
}
inline int read()
{
register int num = 0;
register bool flag = false;
register char c;
while(!isdigit(c = Getchar()))
flag |= c == '-';
while(num = (num << 3) + (num << 1) + (c ^ 48), isdigit(c = Getchar()));
return flag ? -num : num;
}
inline void write(int x)
{
if(x < 0)
Putchar('-'), x = -x;
do
{
*stkpos++ = x % 10 ^ 48;
x /= 10;
} while(x);
while(stkpos-- != stk)
Putchar(*stkpos);
++stkpos;
}
}/*}}}*/
using namespace Fast_IO;
const int maxN = 102;
int n, q, x, y, z, cnt;
int head[maxN], F[maxN][maxN], size[maxN];
bool vis[maxN];
struct Chain
{
int v, w, next;
} chain[maxN << 1];
template<typename _Tp>
inline bool chkmin(_Tp& x, const _Tp& y)
{/*{{{*/
return x > y ? (x = y, true) : false;
}/*}}}*/
template<typename _Tp>
inline bool chkmax(_Tp& x, const _Tp& y)
{/*{{{*/
return x < y ? (x = y, true) : false;
}/*}}}*/
inline void Link(int u, int v, int w)
{
chain[++cnt] = (Chain){v, w, head[u]};
head[u] = cnt;
}
void DFS(int u)
{
vis[u] = true;
for(register int i = head[u]; i; i = chain[i].next)
{
int v = chain[i].v;
if(vis[v])
continue;
DFS(v);
size[u] += size[v] + 1;
for(register int j = std::min(q, size[u]); j; --j)
for(register int k = std::min(j - 1, size[v]); ~k; --k)
chkmax(F[u][j], F[u][j - k - 1] + F[v][k] + chain[i].w);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("temp.in", "r", stdin);
freopen("temp.out", "w", stdout);
#endif
n = read(), q = read();
for(register int i = 1; i < n; ++i)
{
x = read(), y = read(), z = read();
Link(x, y, z);
Link(y, x, z);
}
DFS(1);
write(F[1][q]);
fwrite(obuf, 1, opos - obuf, stdout);
return 0;
}
以上是关于Luogu-P2015 二叉苹果树的主要内容,如果未能解决你的问题,请参考以下文章