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-1]+f[i][k]\}\)。这里的\(j-k-1\)表示以\(num\)为顶点(因为\(num\)可以有多个子树),拥有\(k-1\)个节点的子树。

AC代码

#include<stdio.h>
#include<string.h>
int max(int a,int b){return a>b?a:b;}
int f[310][310],next[310],head[310],s;
int dfs(int num){
    if(head[num]==-1)return 0;//叶节点
    int i,j,k,sum=0,t;
    for(i=head[num];i!=-1;i=next[i]){//遍历该节点所连边
        t=dfs(i);//以i为根的子树节点数
        sum+=t+1;//总和+i
        for(j=sum;j>=0;j--)//节点个数
            for(k=0;k<=t&&k<=j-1;k++)//以i为根的子树f[i][k]+i+以num为根的子树f[num][j-1-k]
                f[num][j]=max(f[num][j],f[num][j-1-k]+f[i][k]);
    }
    return sum;
}
int main(){
    int i,n,m,a;
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    for(i=1;i<=n;i++){
        scanf("%d%d",&a,&s);
        f[i][0]=s;//根节点的学分最大值初始为本身
        next[i]=head[a];//前向星建有向图
        head[a]=i;
    }
    dfs(0);//0为根
    printf("%d",f[0][m]);//以0为根的子树学分最大值
    return 0;
}

原文地址:https://www.cnblogs.com/Potassium/p/10134153.html

时间: 2024-10-08 03:06:01

P2014 选课 题解(树形DP)的相关文章

CH5402 选课【树形DP】【背包】

5402 选课 0x50「动态规划」例题 描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了 N(N≤300) 门的选修课程,每个学生可选课程的数量 M 是给定的.学生选修了这 M 门课并考核通过就能获得相应的学分.在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其他的一些课程的基础上才能选修.例如<Windows程序设计>必须在选修了<Windows操作基础>之后才能选修.我们称<Windows操作基础&

选课【树形dp】

树形dp入门经典题 大意就是学每门课可以获得相应的学分 sc[ i ],但学一门课必须先学习他的先修课 给定能学的课程数,求能得的最大学分. 很容易想象出一个树形结构 设 dp [ u ][ j ] 表示以 u 为根节点选 j 门课的学大得分. 接下来我们可以选择学习 u 的子节点, 也可以继续选择子节点的子节点. 我们枚举学习 u 的子节点的个数 k 可得动态转移方程 dp[u][j] = max(dp[u][j], dp[u][j-k-1]+dp[v][k]+sc[v]); #include

[Luogu2014]选课(树形dp)

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

Luogu P2014 选课 题解报告

题目传送门 [题目大意] 有n门选修课,每一门课都有固定的学分$S_i$,每个学生可以选m门课.有些选修课有先修课,每一门课最多只有一门先修课,求能获得的最多学分. [思路解析] 设f[x][t]表示在以x结点为根的子树中选t门课能获得的最大学分,x的子结点集合为son[x],子结点个数为p,且对于x的第i个子结点son[i],以其为根结点的子树中选课数量为$C_i$,则转移方程为:$$f[x][t]=max(\sum_{i=1}^{p}f[son[i]][c[i]])+s[i](满足\sum_

codevs 1378 选课 (树形DP)

#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,son[310][2],f[310][310],v[310],ans; int init() { int x=0;char s;s=getchar(); while(s<'0'||s>'9')s=getchar(); while(s>='0'&&s<='9'){x=x

内网 可怜与超市题解 树形dp+合并

调过了题比较高兴 首先想到了dp柿子 f[i][j][0/1]代表第i个节点买了j个用(1)没用(0)优惠券的最小花费. 而且是从子节点向父节点转移. f[i][j][0]=min(f[k][l][0]+f[i][j-l][0]) k是i的儿子,l属于sz[i]. f[i][j][1]=min(min(f[k][l][1],f[k][l][0])+f[i][j-l][1]) 同上. 然后暴力转移,发现是n3复杂度,最多T70(再次%%%有钱人用我的柿子暴力卡过) 有钱人的暴力方法:判断当前钱数是

几个树形dp

1.重建道路 树形dp基础题,f[i][j]表示在i这个点我和我的子树联通块大小为j最少砍几条边. 转移的时候,到下一个子树时上一个子树所有答案先++(此树直接砍掉不贡献答案),再继续dp. 注意更新答案时,如果不是跟答案还有+1(砍掉我和我父亲的),不然洛谷会挂四个点QAQ 马上就Noip了我还只能做这种水题QAQ 还挂 //Twenty #include<algorithm> #include<iostream> #include<cstring> #include

【bzoj1907】树的路径覆盖 树形dp

题目描述 输入 输出 样例输入 1 7 1 2 2 3 2 4 4 6 5 6 6 7 样例输出 3 题解 树形dp 设f[x]表示以x为根的子树完成路径覆盖,且x为某条路径的一端(可以向上延伸)的最小路径数,g[x]表示以x为根的子树完成路径覆盖,且x不为某条路径的一端的最小路径数. 那么考虑点x,只有三种情况:单独成路径.与一条子树的链成路径.与两条子树的链成路径. 这三种情况分别对应三种状态转移方程,具体见代码. 然而看到网上题解大把大把的贪心我也是醉了qaq #include <cstd

【bzoj3696】化合物 树形dp

题目描述 首长NOI惨跪,于是去念文化课了.现在,他面对一道化学题.这题的来源是因为在一个奇怪的学校两个化竞党在玩一个奇怪的博弈论游戏.这个游戏很蛋疼,我相信你们也没有兴趣听.由于这个游戏涉及博弈论,因此化竞的同学就要求首长求一个类似SG函数的值.他们手中有一种非常神奇的化合物,它的分子由N个原子组成(不要在意一个原子可能和及其多个原子成键这个细节).这个分子构成一个树结构,1号分子为根.    若两个原子i.j到它们的最近公共祖先的距离分别是Li和Lj,定义它们的Aij值为:Aij=Li  x