題面
題目描述
學校實行學分制。每門的必修課都有固定的學分,同時還必須獲得相應的選修課程學分。學校開設了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的正整數。
輸出格式
只有一個數:實際所選課程的學分總數。
題解
這道題目是一個分組揹包,但是跟一般的分組揹包不同的是,這道題目的約束條件是樹形的。
狀態: 代表第i個結點的子樹,選了j門課的最大學分。
注意點:
以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;
}