P2014 [CTSC1997] 选课
题意:选课,选课数有限制,课程之间有依赖(树状),问能选的最大学分。
好歹是做出来了,虽然感觉写的很史。
我想的是树上背包。
lim[x]表示x的限制数量,它是目标M和子树大小的较小者(目标是尽可能减少背包大小)。dp[x][y]表示的是以x为根,大小为y的子树的学分最大值。然后父节点可以把孩子的dp作为物品,做01背包。
但是要注意,每个孩子只能取一次,也就是说,不能先在孩子的子树里取一个体积较小的“物品”,再取一个较大的“物品”。所以才会有ndp[]这个东西,以保证在孩子的子树里只取一次。
然后0号节点我也设为一门课,但是没有学分,所以dp[][]初值条件会和普通节点有所不同,详见代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define endl '\n'
const int MAX=310;
// const int MOD;
int N,M,ans=LONG_LONG_MIN;
int siz[MAX],val[MAX],lim[MAX];
//siz子树大小 val课程学分 lim子树可选课程上限
int dp[MAX][MAX];//树上背包
int ndp[MAX];//滚动用
vector<int> e[MAX];
void dfs1(int x,int fa){
siz[x]=1;
for(auto t:e[x]){
if(t==fa)continue;
dfs1(t,x);
siz[x]+=siz[t];
}
}
void dfs(int x,int fa){
if(e[x].size()==0&&e[x][0]==fa){
lim[x]=1;
dp[x][1]=val[x];
return;
}
lim[x]=min(siz[x],M);
if(x){
dp[x][1]=val[x];//普通初值条件
for(auto t:e[x]){
if(t==fa)continue;
dfs(t,x);
for(int i=0;i<=lim[x];++i) ndp[i]=dp[x][i];
for(int wei=lim[t];wei;wei--){
// if(x==1&&wei==2){
// for(int i=0;i<=lim[x];++i)cout<<ndp[i]<<" ";
// }
// cout<<endl;
for(int bag=lim[x];bag>=wei+1;bag--){
ndp[bag]=max(ndp[bag],dp[x][bag-wei]+dp[t][wei]);
}
// if(x==1&&wei==2){
// for(int i=0;i<=lim[x];++i)cout<<ndp[i]<<" ";
// }
// cout<<endl;
}
for(int i=0;i<=lim[x];++i) dp[x][i]=ndp[i];
}
}
else{
dp[0][0]=0;//特殊初值条件
for(auto t:e[x]){
// if(t==fa)continue;
dfs(t,x);
for(int i=0;i<=lim[x];++i) ndp[i]=dp[x][i];
for(int wei=lim[t];wei;wei--){
for(int bag=lim[x];bag>=wei;bag--){
ndp[bag]=max(ndp[bag],dp[x][bag-wei]+dp[t][wei]);
}
}
for(int i=0;i<=lim[x];++i) dp[x][i]=ndp[i];
}
}
// cout<<x<<" ";
// for(int i=1;i<=lim[x];i++){
// cout<<dp[x][i]<<" ";
// }
// cout<<endl;
}
void solve(){
memset(dp,0xcf,sizeof dp);
cin>>N>>M;
for(int i=1;i<=N;i++){
int s,k;cin>>s>>k;
e[i].push_back(s);
e[s].push_back(i);
val[i]=k;
}
dfs1(0,-1);
dfs(0,-1);
// for(int i=0;i<=M;i++)ans=max(ans,dp[0][i]);
cout<<dp[0][M]<<endl;
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
// int times;cin>>times;
// while(times--)
solve();
return 0;
}

浙公网安备 33010602011771号