洛谷2014選課
阿新 • • 發佈:2018-11-06
題目描述
在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有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 }