1. 程式人生 > >洛谷2014選課

洛谷2014選課

題目描述

在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有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

 *****揹包類樹形DP

F[i][j]表示以x為根的子樹中選t門課能夠獲得的最高學分

這些點彙總在一起會成為一個森林狀。用0節點把他們歸攏起來。

用分組揹包進行樹形DP狀態轉移。

 1 #include<cstdio>
 2 #include<cstring>
 3
#include<cmath> 4 #include<algorithm> 5 using namespace std; 6 int i,j,f[305][305],t[305],son[305][305],a[305],n,m,s,k; 7 void dp(int x) 8 { 9 f[x][0] = 0; //沒選課 10 for(int i = 1;i <= t[x];i++) //迴圈子節點(物品) 11 { 12 int y = son[x][i]; 13 dp(y); 14 for(int j = m;j >= 0
;j--) // 倒序迴圈當前選課總門數(當前揹包體積) 15 { 16 for(int k = j;k >= 0;k--) //迴圈更深子樹上的選課門數(組內物品) 17 f[x][j] = max(f[x][j],f[x][j - k] + f[y][k]); 18 } 19 } 20 if(x != 0) //x不為0時,選修x本身需要佔用一門課並獲得相應的學分 21 { 22 for(int r = m;r >= 1;r--) 23 { 24 f[x][r] = f[x][r - 1] + a[x]; 25 } 26 } 27 } 28 int main() 29 { 30 scanf("%d %d",&n,&m); 31 for(i = 1;i <= n;i++) 32 { 33 scanf("%d %d",&k,&s); 34 a[i] = s; 35 t[k]++; 36 son[k][t[k]] = i; 37 } 38 dp(0); 39 printf("%d",f[0][m]); 40 return 0; 41 }