Description
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?
Input
第一行有两个整数N,M用空格隔开。(1<=N<=300,1<=M<=200)
接下来的N行,第I+1行包含两个整数ki和si, ki表示第I门课的直接先修课,si表示第I门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。
Output
只有一行,选M门课程的最大得分。
Sample Input
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
Sample Output
13
解题须知:
顾名思义,树型动态规划就是在“树”的数据结构上的动态规划,平时作的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有二种方法既顺推与逆推,而树型动态规划是建立在树上的,所以也相应的有二个方向:
1、叶->根:在回溯的时候从叶子节点往上更新信息
2、根 - >叶:往往是在从叶往根dfs一遍之后(相当于预处理),再重新往下获取最后的答案。
不管是 从叶->根 还是 从 根 - >叶,两者都是根据需要采用,没有好坏高低之分。
分析:在n门课中选出m门课,得到最大的学分。典型的树形DP问题,f[i][j]表示从i中选出j个得到最优解,针对本题可以得到的状态转移方程:
f[i][j]=max(f[i][a],f[k][b]) 其中 k是i的子树,a+b=j。
代码:
import java.util.*;
public class 选课 {
static int[] preCourse=new int[301]; //先选课
static int[] score=new int[301]; //每一门课对应的学分
static int[][] f=new int[301][201]; //f[i][j],表示包括i,选课j门最大学分
static int m,n;
public static void TreeDP(int k,int m) {
//如果选课数为零,终止搜索
if(m==0)
return;
for(int i=1;i<=n;i++) {
//如果课程k的先选课已经选上了或者是没有先选课
if(preCourse[i]==k) {
//记录此时的选课学分
for(int j=0;j<m;j++)
f[i][j]=f[k][j]+score[i];
//继续搜索
TreeDP(i,m-1);
//记录此时选课为k时的学分最大值
for(int j=1;j<=m;j++)
f[k][j]=Math.max(f[i][j-1],f[k][j]);
}
}
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String[] s=new String[4];
n=in.nextInt();
m=in.nextInt();
s=in.nextLine().split(" ");
for(int i=1;i<=n;i++) {
s=in.nextLine().split(" ");
preCourse[i]=Integer.parseInt(s[0]);
score[i]=Integer.parseInt(s[1]);
}
//初始化为没选课,并且每门课的学分都为零
for(int i=0;i<=m;i++) {
f[0][i]=0;
}
TreeDP(0,m);
//输出选课完成后的最大学分
System.out.println(f[0][m]);
}
}