P2014 [CTSC1997]选课 ###K //K
题目链接:https://www.luogu.com.cn/problem/P2014
思路:第一种写法直接以0为根 转换成树上背包 dp[i][j] 代表以i为根 取j个子节点的最大值
注意的是 如果要拿子树上的点,就必须拿到该子树根 所以dp[i][j] 是不取 i 这个根的
第二种写法是 dp[u][i] 是包含根节点u的 最大值
如果是点权的话 是要放在最后 再for一遍 V 把点权加上的
边权的话是在处理子树的时候就要加上, 因为如果点权在处理子树的时候加上的话,就会让每颗
子树都要取a[u] 导致答案变小
写法一
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3e2+10; 4 const int mod=998244353; 5 #define ll long long 6 #define pb push_back 7 #define pi pair<int,int> 8 #define fi first 9 #define sc second 10 11 int n,V; 12 int dp[maxn][maxn]; 13 int w[maxn]; 14 vector<int>E[maxn]; 15 16 void dfs(int u) 17 { 18 for(auto &v:E[u]) 19 { 20 dfs(v); 21 for(int j=V;j>=1;j--) 22 for(int k=0;k<=j-1;k++) 23 dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k-1]+w[v]); 24 } 25 } 26 27 28 int main() 29 { 30 ios::sync_with_stdio(0); 31 cin.tie(0); 32 cin>>n>>V; 33 for(int i=1;i<=n;i++) 34 { 35 int p; 36 cin>>p>>w[i]; 37 E[p].pb(i); 38 } 39 dfs(0); 40 cout<<dp[0][V]<<'\n'; 41 42 43 44 45 }
写法二
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3e2+10; 4 const int mod=998244353; 5 #define ll long long 6 #define pb push_back 7 #define pi pair<int,int> 8 #define fi first 9 #define sc second 10 11 int n,V; 12 int dp[maxn][maxn]; 13 int w[maxn]; 14 vector<int>E[maxn]; 15 16 void dfs(int u) 17 { 18 for(auto &v:E[u]) 19 { 20 dfs(v); 21 for(int j=V;j>=0;j--) 22 for(int k=0;k<=j;k++) 23 dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]); 24 } 25 if(u!=0) 26 for(int i=V;i>=1;i--) 27 dp[u][i]=dp[u][i-1]+w[u]; 28 29 } 30 31 32 int main() 33 { 34 ios::sync_with_stdio(0); 35 cin.tie(0); 36 cin>>n>>V; 37 for(int i=1;i<=n;i++) 38 { 39 int p; 40 cin>>p>>w[i]; 41 E[p].pb(i); 42 } 43 dfs(0); 44 cout<<dp[0][V]<<'\n'; 45 46 47 48 49 }
                    
                
                
            
        
浙公网安备 33010602011771号