前言
在树上搞DP?好高大上的DP。。。
1.思想
外瑞库,康明松。
2.树形DP例题之选课
【题目链接】
洛谷【2014】
【题目描述】
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?
【输入格式】
第一行有两个整数N,M用空格隔开。(1<=N<=300,1<=M<=150)
接下来的N行,第I+1行包含两个整数ki和si, ki表示第I门课的直接先修课,si表示第I门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。
【输出格式】
只有一行,选M门课程的最大得分。
【输入样例】
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
【输出格式】
13
【程序】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include<cstdio> #include<iostream> #define M 500500 using namespace std; int n,m; int head[M],next[M],w[M]; int f[M/100][M/100]; int dfs(int x) { if(head[x]==0) return 0; int ans=0; for(int i=head[x];i;i=next[i]) { int t=dfs(i); ans+=t+1; for (int j=ans;j>=0;j--) { for (int k=0;k<=t;k++) { if (j-k-1>=0) f[x][j]=max(f[x][j],f[x][j-k-1]+f[i][k]); } } } return ans; } int main() { scanf("%d%d",&n,&m); int ta,tb; for(int i=1;i<=n;++i) { scanf("%d%d",&ta,&tb); next[i]=head[ta]; head[ta]=i; w[i]=tb; } for(int i=0;i<=n;++i) f[i][0]=w[i]; dfs(0); printf("%d",f[0][m]); return 0; }
|