[題解]P2014 選課-樹型依賴的揹包
阿新 • • 發佈:2018-11-04
題目連結:https://www.luogu.org/problemnew/show/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門課程的最大得分。
解題思路:
f[i][j][k]表示以i為根的子樹,前j個結點,選了k個結點的最大得分。
這個狀態就是有樹型依賴的揹包問題。
考慮優化狀態,f[i][j]表示以i為根的子樹,選了k個結點的最大得分。
這是0/1揹包從2維優化到1維的思路。
還可以用滾動陣列.
程式碼:
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<cmath> #include<algorithm> #define R register #define ll long long int using namespace std; const int N=308; int n,m,sco[N],f[N][N],num,head[N],fa[N]; struct E{ int nxt,to; }e[N<<2]; inline void add(R intu,R int v) { e[++num].nxt=head[u]; e[num].to=v; head[u]=num; } inline void dfs(R int pos,R int fa) { for(R int i=head[pos];i;i=e[i].nxt) { R int v=e[i].to; if(v!=fa) { dfs(v,pos); for(R int j=m;j>=0;j--)//列舉總數 for(R int k=0;k<=j;k++)//列舉選多少 f[pos][j]=max(f[pos][j],f[pos][j-k]+f[v][k]); } } if(pos!=0) for(R int i=m;i>=1;i--) f[pos][i]=f[pos][i-1]+sco[pos]; } int main(){ scanf("%d%d",&n,&m); for(R int i=1;i<=n;i++) { R int v; scanf("%d%d",&v,&sco[i]); add(v,i); add(i,v); } dfs(0,-1); printf("%d",f[0][m]); return 0; }