luogu P2014 選課
阿新 • • 發佈:2018-12-09
luogu P2014 選課
42行程式碼或成此題最X題解?
一看:樹形dp
f[i][j]表示以i為根的子樹選了j個課所獲得的最大學分
等等,課可以重複選!
要用揹包搞搞嘍
每次列舉子節點
對每個子節點先進行樹形dp
再對父節點進行揹包
這裡可以把0看成一個假根,可以不選
所以對於每個不是假根的節點,一定要選自己
怎麼選?
先揹包,揹包好了後f[x][i]=f[x][i-1]+s[i]
完美~
std:
#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m;
struct node{//定義node
vector<int> q;
int val;
}s[N];
int f[N][N];//以i為根的子樹選了j個課所獲得的最大學分
void dfs(int x){
f[x][0]=0;//一個都不選
for(int i=0;i<s[x].q.size();i++){//遍歷兒子
int y=s[x].q[i];
dfs(y);//先對兒子進行dfs
for(int j=m;j>=0;j--){//列舉x的空間
for(int k=j;k>=0;k--){//列舉y的空間
if(j-k>=0)
f[x][j]=max(f[x][j],f[ x][j-k]+f[y][k]);
}
}
}
if(x!=0){//是自己要選的 (非假根)
for(int i=m;i>0;i--)
f[x][i]=f[x][i-1]+s[x].val;//選自己
}
for(int i=0;i<=m;i++) {
printf("%d %d %d\n",x,i,f[x][i]);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x,y;
scanf("%d%d",&x,&y);
s[ x].q.push_back(i);
s[i].val=y;
}
memset(f,0xcf,sizeof(f));//將初始值設為負的極大值
dfs(0);//從假根開始dfs
printf("%d\n",f[0][m]);//答案在假根裡
return 0;
}