P2014 选课(树形背包)

P2014 选课

题目描述

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

输入输出格式

输入格式:

第一行有两个整数N,M用空格隔开。(1<=N<=300,1<=M<=300)

接下来的N行,第I+1行包含两个整数ki和si, ki表示第I门课的直接先修课,si表示第I门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。

输出格式:

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

输入输出样例

输入样例#1: 复制
7  4
2  2
0  1
0  4
2  1
7  1
7  6
2  2
输出样例#1: 复制
13


code

 1 #include<cstdio>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 
 6 const int MAXN = 310;
 7 
 8 struct Edge{
 9     int to,nxt;
10 }e[100100];
11 int head[100100],tot;
12 int val[MAXN],dp[MAXN][MAXN];
13 //dp[i][j]以i为根的树中,选了j节课的最大学分。 
14 inline int read() {
15     int x = 0,f = 1;char ch = getchar();
16     for (; ch<'0'||ch>'9'; ch = getchar())
17         if (ch=='-') f = -1;
18     for (; ch>='0'&&ch<='9'; ch = getchar())
19         x = x*10+ch-'0';
20     return x*f;
21 }
22 inline void add_edge(int u,int v) {
23     e[++tot].to = v,e[tot].nxt = head[u],head[u] = tot;
24 }
25 void dfs(int u,int m) {
26     dp[u][1] = val[u];
27     for (int i=head[u]; i; i=e[i].nxt) {
28         int v = e[i].to;
29         dfs(v,m);
30         for (int j=m; j>=2; --j) 
31             for (int k=0; k<j; ++k) 
32                 dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]);
33     }
34 }
35 int main() {
36     
37     int n = read(),m = read();
38     for (int a,i=1; i<=n; ++i) {
39         a = read();val[i] = read();
40         add_edge(a,i); 
41     }
42     val[0] = 0;
43     dfs(0,m+1);
44     printf("%d",dp[0][m+1]);
45     return 0;
46 }
原文地址:https://www.cnblogs.com/mjtcn/p/7898379.html