P2014 选课 - 树形DP[树形背包DP]

P2014 选课

传送门

思路:

树形背包DP模型,\(f[i,j]\)表示以\(i\)为根的子树中,选了\(j\)门课的最大学分。树形DP常以子树\(i\)为阶段。树形背包DP相当于树上分组背包DP。\(f[u,j]=max\{f[u,j],f[u,j-k]+f[v,k]~|~v\in~son(u)\}\)。我们枚举从u的子树v中选的课数k,将\(f[v,k]\)作为获得的价值加到\(f[u,j-k]\)得到\(f[u,j]\)。注意到当前子树根节点u是必须选的,所以要从\(f[u,j-1]\)加上\(a[u]\)转移到\(f[u,j]\)。最终答案为\(f[1,M]\)。

Tips:

1.注意到题目给定的是一个森林,我们可以建一个虚拟节点0,将森林转化为一个以0为根节点的树,然后就可以直接树形DP了。

注意0号节点不代表课程,所以不需要从\(f[0,j-1]+a[0]\)转移到\(f[0,j]\)。

2.初始化DP数组\(f[u,0]=0\)。

3.对于树形DP的判重,好像记录\(vis\)数组 和 记录\(fa\)是等效的。

4.树形DP,别忘了DFS(v)啊。。。

AC Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 300+100;
int n,m;
int fa[N],a[N];
struct node{int to,nxt;}e[N<<1];
int head[N],tot;
void add(int u,int v){e[++tot].to=v,e[tot].nxt=head[u],head[u]=tot;}
bool vis[N];int f[N][N];
void dfs(int u){
    f[u][0]=0;vis[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;if(vis[v]) continue;
        dfs(v);
        for(int j=m;j>=0;j--){
            for(int k=j;k>=0;k--){
                if(j-k>=0) f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
            }
        }
    }
    if(u!=0) for(int j=m;j;j--) f[u][j]=f[u][j-1]+a[u];
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&fa[i],&a[i]),add(i,fa[i]),add(fa[i],i);
    dfs(0);
    printf("%d",f[0][m]);
    return 0;
}

原文地址:https://www.cnblogs.com/Loi-Brilliant/p/9612426.html

时间: 2024-12-08 20:18:44

P2014 选课 - 树形DP[树形背包DP]的相关文章

P2014 选课 题解(树形DP)

题目链接 P2014 选课 解题思路 树形动归,用\(f[i][j]\)表示以\(i\)为根,\(j\)个子节点(不包括自己)的最大学分 首先根据题意建图,用根节点\(0\)将森林连成树. 从根节点开始\(DFS\)遍历,遍历到叶节点后回溯,回溯过程中将\(f[i][j]\)更新,利用背包的思想. \(DFS\)过程中,\(num\)为离根节点0更近的定点,遍历的\(i\)为\(num\)的子节点,容易得出递推关系式: \(f[num][j]=max\{f[num][j],f[num][j-k-

背包DP 方案数---P1832 A+B Problem(再升级)

P1832 A+B Problem(再升级) 题面描述 给定一个正整数n,求将其分解成若干个素数之和的方案总数. 题解 我们可以考虑背包DP实现 背包DP方案数板子题 f[ i ] = f[ i ] + f[ i - a[j] ] f[ j ] 表示数字 j 用若干个素数表示的方案总数 注意 1.线性筛不要写错: 1)not_prime[maxn] maxn>=n   2)memset not_prime 数组之后,0,1初始化不是素数 2.方案数 DP 数组要开 long long 代码 #i

Luogu P2014 选课 (树形DP)

题目 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b).一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少? 输入输出格式 输入格式: 第一行有两个整数N,M用空格隔开.(1<=N<=300,1<=M<=300) 接下来的N行,第i+1行

洛谷P2014 选课 (树形dp)

10月1日更新.题目:在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b).一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?输入第一行有两个整数N,M用空格隔开.(1<=N<=200,1<=M<=150)接下来的N行,第I+1行包含两个整数ki和s

树形DP 洛谷P2014 选课

P2014 选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b).一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少? 输入输出格式 输入格式: 第一行有两个整数N,M用空格隔开.(1<=N<=300,1<=M<=300) 接下来的N行

hdu4003 树形dp+分组背包

http://acm.hdu.edu.cn/showproblem.php?pid=4003 Problem Description Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on

hdu 1561The more, The Better(树形dp&amp;01背包)

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4949    Accepted Submission(s): 2918 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝

hdu1561:树形背包dp

给定n个地点,每个地点藏有cost[i]的宝物,取得某些宝物有时需要先取其他宝物,现在让我们选m个地点问最多可以选多少宝物? 还是挺裸的树形背包dp吧,不难,关键还是中间dp的部分.可以做模板了->_-> 注意点:多组数据的话如果第一组对了然后其他都错了,那么很有可能是初始化的时候漏了.这次找可很久才知道差了e[0].clear().平时的习惯都是从1开始. --------------------------------------------------------------------

POJ 2486 Apple Tree 树形DP+分组背包

链接:http://poj.org/problem?id=2486 题意:一棵(苹果)树,树上有N个结点(N<=100),起点是结点1.每个结点上有若干个苹果,我可以进行K步操作(K<=200),每次操作是从当前结点移动到相邻的结点,并且到了相邻的结点以后会吃掉上面的所有苹果并且苹果不再长出来,相邻是指两个结点之间有边相连.问在K步操作之后最多可以吃掉多少个苹果. 思路:刚入手的时候觉得是一般的树形背包问题,dp[i][j]代表的是以i为根的子树中走j个结点所能吃到的苹果数,来进行状态转移,但