Loj10154 選課

試題描述:ios

大學實行學分制。每門課程都有必定的學分,學生只要選修了這門課並經過考覈就能得到相應學分。學生最後的學分是他選修各門課的學分總和。
每一個學生都要選擇規定數量的課程。其中有些課程能夠直接選修,有些課程須要必定的基礎知識,必須在選了其餘的一些課程基礎上才能選修。例如《數據結構》必須在選修了《高級語言程序設計》後才能選修。咱們稱《高級語言程序設計》是《數據結構》的先修課。每門課的直接先修課最多隻有一門。兩門課也可能存在相同的先修課。爲便於表述每門課都有一個課號,課號依次爲 1,2,3…
上例中課號1是課號2的先修課,即若是要先修課號2,則課號1一定已被選過。一樣,若是要選修課號3,那麼課號1和課號2都必定被選修過。
學生不可能學完大學開設的全部課程,所以必須在入學時選定本身要學的課程。每一個學生可選課程的總數是給定的。如今請你找出一種選課方案,使得你能獲得的學分最多,而且必須知足先修課優先的原則。假定課程間不存在時間上的衝突。git

首先能一眼看出來,這些課程是一個樹形結構,對於每個節點i,都須要判斷它的全部兒子是否取,又往下取多少。數據結構

這樣咱們把問題轉化成了一個分組揹包:對於每個節點,每一顆子樹就是一組,每一組又m(也就是選課數)個物品,第i物品的體積是i,價值是f[j][i](j爲當前兒子)spa

而後轉移方程就能夠變爲f[i][j][k]表示在以i爲根節點的子樹中,第j組,取k個物品的最優值。設計

易獲得:f[i][j][k]=max(f[i][j][k],f[i][j-1][k-q](q爲枚舉物品)+f[i][y][q])(y爲子節點)code

而後,咱們發現能夠把j的那一位壓去,可是注意循環要倒着寫。blog

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#define MAXN 1010
#define in(a) a=read()
#define REP(i,k,n)  for(int i=k;i<=n;i++)
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,m;
int total,head[MAXN],to[MAXN<<1],nxt[MAXN<<1],f[MAXN][MAXN],s[MAXN];
inline void adl(int a,int b){
    total++;
    to[total]=b;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void dfs(int i){
    for(int e=head[i];e;e=nxt[e]){
        dfs(to[e]);
        for(int j=m;j>=0;j--)
            REP(k,0,j)
                f[i][j]=max(f[i][j],f[i][j-k]+f[to[e]][k]);
    }
    if(i)  for(int j=m;j>0;j--)  f[i][j]=f[i][j-1]+s[i];
    return ;
}
int main(){
    in(n),in(m);
    int a,b;
    REP(i,1,n)  in(a),in(s[i]),adl(a,i);
    dfs(0);
    cout<<f[0][m];
    return 0;
}
相關文章
相關標籤/搜索