1. 程式人生 > >洛谷P2014

洛谷P2014

他能 nbsp def region -o ret names ring 忘記

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

也是樹形dp,但這裏用到了左兒子右兄弟(就是多叉樹轉二叉樹)的奇技淫巧(第一次聽說這玩意兒還是在2017WC的第二課堂上。。。那時還不以為然)。
既然是森林,把0設為總根是很自然的想法,就是不要忘記m需要+1(霧)因為多了0這門沒有價值的課。

#include<iostream>
#include<cstdio>
#include
<cstring> #include<algorithm> #include<cmath> #define N 305 using namespace std; int n,m,son[N],bro[N],f[N][N],used[N]; void add(int fa,int i) { bro[i]=son[fa]; son[fa]=i; } void dfs(int x) { used[x]=1; for(int i=son[x];i;i=bro[i]) if(!used[i]) { dfs(i);
for(int j=m+1;j>1;j--) for(int k=j-1;k>=1;k--) f[x][j]=max(f[x][j],f[x][k]+f[i][j-k]); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int a,b; scanf("%d%d",&a,&b); f[i][1]=b; add(a,i); } dfs(0); printf("%d",f[0][m+1]); return 0; }
另外,做的時候突然卡住了,因為沒有想通f[i][j]表示的是一定要選第i門課的情況,所以不會產生有先修課沒學過的情況。我還是太菜了。。。

洛谷P2014