ICode9

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

[oiclass1454]选课:树上背包

2022-01-11 12:05:55  阅读:140  来源: 互联网

标签:oiclass1454 学分 课程 选课 int leq 背包 修课


题目

在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有 \(N\) 门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程 \(a\) 是课程 \(b\) 的先修课即只有学完了课程 \(a\),才能学习课程 \(b\))。一个学生要从这些课程里选择 \(M\) 门课程学习,问他能获得的最大学分是多少?

输入

第一行有两个整数 \(N,M\) 用空格隔开。(\(1\leq N \leq 300,1\leq M\leq 200\))
接下来的 \(N\) 行,第 \(i+1\) 行包含两个整数 \(k_i\) 和 \(s_i\), \(k_i\) 表示第 \(i\) 门课的直接先修课,\(s_i\) 表示第 \(i\) 门课的学分。若 \(k_i=0\) 表示没有直接先修课(\(1\leq k_i \leq N, 1\leq s_i \leq 20\))。

输出

只有一行,选 \(M\) 门课程的最大得分。

输入样例

7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2

输出样例

13

题解

经典题,传统解法是将讲多叉树转化成二叉树,然后在二叉树上进行树形DP,现在使用树上背包来解会更简单。
需要事先学习树上背包,理解分组背包的求法,理解如何将问题转化成树上背包问题。
本题有两种定义方式。

1

定义\(f[i][j]\)表示以i为根选择j门课程的最大得分(包含i的结点),代码如下:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=300+5;
vector<int> g[N];
int n,m,u,v,w,f[N][N],s[N];
void dfs(int u){
	for(int i=1;i<=m;i++)f[u][i]=s[u];
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		dfs(v);
		for(int j=m;j>=0;j--){
			for(int k=0;k<j;k++){
				f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
			}
		}
	}
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1,x;i<=n;i++){
		scanf("%d %d",&x,&s[i]);
		g[x].push_back(i);
	}
	m++;
	dfs(0);
	printf("%d",f[0][m]);
}
2

定义\(f[i][j]\)表示以i为根选择j门课程的最大得分(不包含i的结点),代码如下:

点击查看代码
#include<iostream>
#include<vector>
using namespace std;
vector<int> g[301];
int n,m,x,s[301],f[301][201];
void dfs(int u){
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        dfs(v);
        for(int j=m;j>=0;j--){
            for(int k=0;k<j;k++){
                f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+s[v]);
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>x>>s[i];
        g[x].push_back(i);
    }
    dfs(0);
    cout<<f[0][m];
}

标签:oiclass1454,学分,课程,选课,int,leq,背包,修课
来源: https://www.cnblogs.com/chxulong/p/15787674.html

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

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

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

ICode9版权所有