P2014 选课 (树上背包)

树上背包:

树形背包就是原始的树上动归+背包,一般用来处理以一棵树中选多少点为扩展的一类题,基本做法与树上dp无异,不过在状态转移方程中会用到背包的思想。

它基本上是这个样子的:

存图),然后dfs进去补全子节点的信息,f数组的意思是以fa为中转点,找出fa往下的可取1~j个点时各自的最大收益。

void dfs(int fa){
    for(int i=0;i<son[fa].size();i++){
        int ny=son[fa][i];
        dfs(ny);
        for(int j=m+1;j>=1;j--){
            for(int k=j-1;k>=0;k--){
                f[fa][j]=max(f[fa][j],f[fa][j-k]+f[ny][k]);
            }
        }
    }
}

选课这题基本上就是树上背包的板子题了:

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1)+1

const double eps = 1e-10;
const int maxn = 310;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

struct edge {
    int v,nxt;
}e[maxn];

int head[maxn],w[maxn],f[maxn][maxn];
int fa[maxn];
int cnt;
int n,m;

void add_edge(int u,int v) {
    e[++cnt].v = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

void dfs(int x) {
    for (int i = head[x];~i;i = e[i].nxt) {
        int v = e[i].v;
        dfs(v);
        for (int j = m+1;j >= 1;j--) {
            for (int k = j-1;k >= 0;k--)
                f[x][j] = max(f[x][j],f[v][k]+f[x][j-k]);
        }
    }
}

int main() {
    cnt = 0;
    memset(head,-1, sizeof(head));
    cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        int u,v;
        cin >> u >> v;
        fa[i] = u;
        add_edge(u,i);
        f[i][1] = v;
    }
    dfs(0);
    cout << f[0][m+1] << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/-Ackerman/p/12337944.html

时间: 2024-10-29 02:39:25

P2014 选课 (树上背包)的相关文章

luogu 2014 选课 树上背包

树上背包 #include<bits/stdc++.h> using namespace std; const int N=310; const int inf=0x3f3f3f3f; vector<int> son[N]; int f[N][N],s[N],n,m; void dfs(int u){ f[u][0]=0; for(int i=0;i<son[u].size();i++){ int v=son[u][i]; dfs(v); for(int j=m;j>0

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]\

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-

MZOJ 1132 &amp;&amp; LuoGu P2014 选课

MZOJ 1132 && LuoGu P2014 选课    [传送门] #include<bits/stdc++.h> #define maxn 100000 #define maxm 500 using namespace std; int k=0,head[maxn]; int f[maxm][maxm],w[maxn]; int ans=0; int N,M; struct node{ int v,nxt; }e[maxn<<1]; void adde(in

树形DP 洛谷P2014 选课

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

【BZOJ】4033: [HAOI2015]树上染色 树上背包

[题目]#2124. 「HAOI2015」树上染色 [题意]给定n个点的带边权树,要求将k个点染成黑色,使得 [ 黑点的两两距离和+白点的两两距离和 ] 最大.n<=2000. [算法]树上背包 [题解]设f[i][j]表示子树i中有j个黑点对答案的贡献(包括点 i 到父亲的边 p ),由于边p的贡献只和 j 有关,所以最后再统计. 所以做树上背包即可,注意这题特殊在f[x][0]≠0,所以初始f[x][k]+=f[y][0],然后不要把0作为物品. 最后统计边p的贡献:w[p] *(子树内黑点

HihoCoder 1055 刷油漆 (树上背包)

题目:https://vjudge.net/contest/323605#problem/A 题意:一棵树,让你选择m个点的一个连通块,使得得到的权值最大 思路:树上背包,我们用一个dp数组,dp[i][j] ,代表以i为根时的选其子树j个节点所得到的最大值,然后我们对于每个以i为根我们当做有m件物品,然后对于不同的子树当作不同的分组即可 #include<bits/stdc++.h> #define maxn 105 #define mod 1000000007 using namespac

LuoGu P2014选课(人生第一个树上背包)

(著名哲学家沃兹基硕德曾经说过:“$QuickSilverX$ $is$ $a$ $BB$”) 就是课与课可能有一些优先关系 这种关系我们可以通过图论建模来解决 不难发现,若将优先选修课向当前课连边,就会生成森林(每门课只有一个选修课,也就只有一条入边) 将所有无入边(没有优先课)的结点与0相连,形成树 ~~不难~~发现这是一个树上DP与背包... 树本身就是个递归的结构,我们每个结点的状态肯定是先递归处理儿子结点的状况来转移的 定义状态 $F[i][j][k]$ 表示第 $i$ 的前 $j$

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_