HLOJ456 選課

題面

題目描述
學校實行學分制。每門的必修課都有固定的學分,同時還必須獲得相應的選修課程學分。學校開設了N(N < 300)門的選修課程,每個學生可選課程的數量M是給定的。學生選修了這M門課並考覈通過就能獲得相應的學分。
  在選修課程中,有些課程可以直接選修,有些課程需要一定的基礎知識,必須在選了其它的一些課程的基礎上才能選修。例如《Frontpage》必須在選修了《Windows操作基礎》之後才能選修。我們稱《Windows操作基礎》是《Frontpage》的先修課。每門課的直接先修課最多隻有一門。兩門課也可能存在相同的先修課。每門課都有一個課號,依次爲1,2,3,…。 例如:這裏寫圖片描述
  上例中1是2的先修課,即如果要選修2,則1必定已被選過。同樣,如果要選修3,那麼1和2都一定已被選修過。   你的任務是爲自己確定一個選課方案,使得你能得到的學分最多,並且必須滿足先修課優先的原則。假定課程之間不存在時間上的衝突。
輸入格式
輸入文件的第一行包括兩個整數N、M(中間用一個空格隔開),其中1≤N≤300,1≤M≤N。
以下N行每行代表一門課。課號依次爲1,2,…,N。每行有兩個數(用一個空格隔開),第一個數爲這門課先修課的課號(若不存在先修課則該項爲0),第二個數爲這門課的學分。學分是不超過10的正整數。
輸出格式
只有一個數:實際所選課程的學分總數。

題解

這道題目是一個分組揹包,但是跟一般的分組揹包不同的是,這道題目的約束條件是樹形的。
狀態:f[i][j] 代表第i個結點的子樹,選了j門課的最大學分。

f[u][t]=maxi=1pci=t1{i=1pf[yi][ci]}+score[u]

注意點:
以0爲根節點的同時,要記住0這門課是沒有學分的。
如果是0就直接轉移。

code

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int num=0;
    char c=' ';
    bool flag=true;
    for(;c>'9'||c<'0';c=getchar())
    if(c=='-')
    flag=false;
    for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
    return flag ? num : -num;
}
namespace graph{
    const int maxn=302;
    int n,m,score[maxn];
    vector<int>G[maxn];
    void init(){
        n=read();m=read();
        for(int i=1;i<=n;i++){
            int fa=read();
            score[i]=read();
            G[fa].push_back(i);
        }
    }
}using namespace graph;
int f[maxn][maxn];
void dp(int u){
    f[u][0]=0;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        dp(v);
        for(int t=m;t>=0;t--)
            for(int j=t;j>=0;j--)
                f[u][t]=max(f[u][t],f[u][t-j]+f[v][j]);
    }
    if(u!=0)
        for(int t=m;t>0;t--)
            f[u][t]=f[u][t-1]+score[u];
}
int main(){
    init();
    dp(0);
    printf("%d\n",f[0][m]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章