ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

选课【树形dp】

2020-04-07 22:01:39  阅读:177  来源: 互联网

标签:选课 int len 树形 maxn include 节点 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<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
typedef long long ll;
using namespace std;
const int maxn = 2000;
int m, n;
int dp[maxn][maxn], sc[maxn], fa[maxn];
struct edge{
    int x, y, next;
}a[maxn];
int head[maxn], len = 0;
void add(int x, int y){
    a[++len].x = x;
    a[len].y = y;
    a[len].next = head[x];
    head[x] = len;
}
int dfs(int u){
    int cnt = 0; //表示节点 u 下总共有多少门课
    for(int i=head[u]; i; i=a[i].next){ // 枚举 u 的子节点
        int v = a[i].y;
        cnt += dfs(v)+1;              // 更新课程数
        for(int j=min(cnt,m); j>=1; j--){ // 在 u 下选 j 门课, 01背包注意倒序
            for(int k=0; k<j; k++){  // 枚举选择子节点的子节点个数
                dp[u][j] = max(dp[u][j], dp[u][j-k-1]+dp[v][k]+sc[v]);
            }
        }
    }
    return cnt;
}
int main(){
    scanf("%d%d", &m, &n);
    for(int i=1; i<=m; i++){
        scanf("%d%d",&fa[i],&sc[i]);
        add(fa[i],i);
    }
    dfs(0);
    printf("%d\n",dp[0][n]);
    return 0;
}

这里还有一个技巧,如果没有先修课就让0和他连接,最后得到一棵0为根节点的数,dfs(0)即可

标签:选课,int,len,树形,maxn,include,节点,dp
来源: https://www.cnblogs.com/hzoi-poozhai/p/12638445.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有