P2014

题意

  • 从一棵树中选择m条与根节点直接/间接相连的点,使得总权值最大

DP(树上背包)

状态: dp[i][j]表示在以i为根的子树中,选择了j个点的权值最大值

转移

  • 选择第k个点:dp[i][j]=dp[i][jk]+dp[to][k]
  • 不选第k个点:dp[i][j]=dp[i][j]

决策:dp[i][j]=max(dp[i][j],dp[i][jk]+dp[to][k])

细节

  • k=0时没有父亲->把0作为根节点,从0开始DFS
  • 因为多加了一个0节点,所以边数m+1

代码

#include <bits/stdc++.h>
using namespace std;
int n,m;
int dp[310][310];
int s,k;
struct edge{
int to,next;
}edge[310];
int head[310],cnt;
void insert(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void DFS(int x){
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
DFS(to);
//转化成01背包:背包大小为m,物品大小为k
for(int j=m;j>0;j--){ //想要到达x的儿子必须走x,所以不存在不选x而选x的儿子,即j不为0
for(int k=0;k<j;k++){ //j-k不为0(理由同上),所以k<j而不是k<=j
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[to][k]);
}
}
}
}
int main(){
// freopen("1.in","r",stdin);
cin>>n>>m;
m++;
for(int i=1;i<=n;i++){
cin>>s>>dp[i][1]; //必须选自己
insert(s,i);
}
DFS(0);
cout<<dp[0][m]<<"\n";
}
posted on   Bubble_e  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话



点击右上角即可分享
微信分享提示