1. 程式人生 > >luogu P2014 選課

luogu P2014 選課

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; }