P2015 二叉苹果树 二叉树dp
P2015 二叉苹果树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这道题之所以可以不用背包树形的原因是:它一个经典二叉树dp问题
令son[x][0]为x的左儿子,son[x][1]为x的右儿子
对于x节点,肯定是由左边和右边转移过来的,这就是二叉树dp的特点。
对于左边而不是左儿子,我们留L条边,右边R=i-m;
转移: if(L==0) dp[x][i]=max(dp[x][i],dp[son[x][1]][i-1]+val[x][son[1]]); //全取右边
else if(R==0) dp[x][i]=max(dp[x][i],dp[son[x][0]][i-1]+val[x][son[0]]); //全取左边
else dp[x][i]=max(dp[x][i],dp[son[x][0]][L-1]+val[x][son[0]]+dp[son[x][1]][R-1]+val[x][son[1]]);
最后的答案为dp[1][m]
Code:
#include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pb push_back #define popb pop_back #define fi first #define se second const int N=200; //const int M=200; //const int inf=0x3f3f3f3f; //const ll INF=0x3ffffffffffff; int T,n,m; vector<int> g[N],son[N]; int val[N][N],dp[N][N]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } void dfs(int x,int fa) { for(auto v:g[x]) { if(v==fa) continue; son[x].pb(v); dfs(v,x); } if(!son[x].size()) return; for(int j=1;j<=m;j++) // 第x个节点保存 j 个树枝 { for(int L=0;L<=j;L++) //取x左节点 L 个树枝 { int R; if(L==0) dp[x][j]=max(dp[x][j],dp[son[x][1]][j-1]+val[x][son[x][1]]); else if(L==j) dp[x][j]=max(dp[x][j],dp[son[x][0]][j-1]+val[x][son[x][0]]); else { int R=j-L; dp[x][j]=max(dp[x][j],dp[son[x][0]][L-1]+val[x][son[x][0]]+dp[son[x][1]][R-1]+val[x][son[x][1]]); } } } } int main() { // freopen("","r",stdin); // freopen("","w",stdout); n=read(),m=read(); for(int i=1;i<n;i++) { int u=read(),v=read(),t=read(); g[u].pb(v); g[v].pb(u); val[u][v]=val[v][u]=t; } dfs(1,0); printf("%d",dp[1][m]); return 0; }