luogu P2015 二叉苹果树
Posted ck666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P2015 二叉苹果树相关的知识,希望对你有一定的参考价值。
P2015 二叉苹果树
题目描述
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
2 5
\\ /
3 4
\\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。
输入输出格式
输入格式:
第1行2个数,N和Q(1<=Q<= N,1<N<=100)。
N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
每根树枝上的苹果不超过30000个。
输出格式:
一个数,最多能留住的苹果的数量。
输入输出样例
输入样例#1:
5 2 1 3 1 1 4 10 2 3 20 3 5 20
输出样例#1:
apple_tree
apple apple tree
21
树上的背包问题,很容易就想到如果删除一个子节点,那么以这个节点的棵子树就会全部删除,那么对这个子树删除的节点就不能超过子节点个数。
所以我们先dfs一边,求出有多少一个节点有多少子节点,并标记处father,保证不会到father
f[i][j]<在i这个子树中删除j个边的最大值,然后贪心维护最大就好了
#include<iostream> #include<cstdlib> #include<cstdio> #include<algorithm> #include<queue> #define ll long long using namespace std; const int maxn=150; int read(){ int an=0,f=1;char ch=getchar(); while(!(\'0\'<=ch&&ch<=\'9\')){if(ch==\'-\')f=-1;ch=getchar();} while(\'0\'<=ch&&ch<=\'9\'){an=an*10+ch-\'0\';ch=getchar();} return f*an; } int f[maxn],dp[maxn][maxn],cnt,fa[maxn],son[maxn],Q,n; bool vis[maxn],vis2[maxn]; struct saber{ int to,nex,wi; }b[maxn<<1]; void add(int x,int y,int z){ cnt++; b[cnt].nex=f[x]; b[cnt].to=y; f[x]=cnt; b[cnt].wi=z; } void dfs(int x){ vis[x]=1;son[x]=1; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(!vis[v]){ dfs(v); fa[v]=x; son[x]+=son[v]; } } } void DP(int x){ vis2[x]=1; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(fa[x]!=v){ DP(v); for(int j=min(son[x],Q);j>0;j--) for(int k=min(j,Q);k>0;k--) dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k-1]+b[i].wi); } } } int main(){ n=read();Q=read(); for(int i=1;i<n;i++){ int x=read(),y=read(),z=read(); add(x,y,z); add(y,x,z); } dfs(1); DP(1); cout<<dp[1][Q]; return 0; }
by:s_a_b_e_r
楼上一直坚持两遍dfs,其实一遍就好了啊qwq
而且既然只向下dp,存单向边就可以啦(但是要存一下father)
因为是二叉树所以非常好办
如果点x的子树一共要保留i根树枝
肯定是一部分(j)分给左子树,剩下的(i-j)给右子树
于是就可以愉快地填表DP了^_^
#include<iostream> #include<cstdio> using namespace std; const int N=109; int n,q,p[N],fa[N],f[N][N],cnt,son[N]; struct edge{ int to,nex,val; }e[N<<1]; void add(int u,int v,int w) { ++cnt; e[cnt].to=v; e[cnt].nex=p[u]; p[u]=cnt; e[cnt].val=w; } void dfs(int u) { son[u]=1; for(int i=p[u];i;i=e[i].nex) { int v=e[i].to; dfs(v); son[u]+=son[v]; for(int j=min(q,son[u]);j>=1;--j) for(int k=min(j,son[u]);k>=1;--k) f[u][j]=max(f[u][j],f[u][j-k]+f[v][k-1]+e[i].val); } } int main() { scanf("%d%d",&n,&q); for(int i=1;i<n;++i) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if(fa[y]){fa[x]=y;add(y,x,z);} else {fa[y]=x;add(x,y,z);} } dfs(1); cout<<f[1][q]<<endl; return 0; }
by:wypx
s:I have an apple……
w:I have an another apple……apple tree!!!
以上是关于luogu P2015 二叉苹果树的主要内容,如果未能解决你的问题,请参考以下文章