This paper mainly summarizes some difficulties and details of tree dp.
What is a tree dp
As the name suggests, it is a dp that looks like a tree structure and is carried out on a tree.
The tree dp has a more routine state definition, that is to define \ (dp[i] \) to represent the maximum / minimum value of the subtree with \ (I \) as the root node.
The general tree dp is realized by dfs.
Bare tree dp
Here are some bare trees dp:
2.P1352 dance without boss This question is very important. It represents a kind of tree dp with classification, that is, it records some information of this state in one dimension (because it will have influence)
4.P1131 [ZJOI2007] temporal synchronization Difficult naked questions(
5.P2585 [ZJOI2006] three color binary tree It's a bit like a dance without a boss
For details, give a template (maximum subtree and)
int dfs(int x,int fa){//For a rootless tree, there is one more fa dp[x]=a[x]; for(ri i=0;i<T[x].size();i++){ int y=T[x][i]; if(y==fa)continue; dfs(y,x); if(dp[y]>0)dp[x]+=dp[y]; } ans=max(ans,dp[x]); }
Tree Backpack
Let's talk about this in detail.
The knapsack on the tree can be said to be a dependent dp, because the \ (dp \) value between its subtree and subtree is related.
So we can treat it as a backpack.
Ke AI's small template.
The knapsack on the tree has three cycles: child nodes, capacity, and the capacity allocated to each child tree.
Attention is rootless tree!
int dfs(int x,int fa){ int sum=0; for(ri i=0;i<T[x].size();i++){ int y=T[x][i].pos; if(y==fa)continue; sum=sum+dfs(y,x)+1; for(ri j=min(sum,q);j>=0;j--){//capacity for(ri k=0;k<=j-1;k++){//Number of branches allocated dp[x][j]=max(dp[x][j],dp[y][k]+dp[x][j-k-1]+T[x][i].w); } } } return sum; }
2.P2014 [CTSC1997] course selection
Wrasar was impressed by this problem because he blurted out a wrong code (even the equation was wrong) and handed it in to AC(((
Let's talk about the positive solution and some points for attention qwq
(1) The output answer is \ (dfs(0,n+1) \), because when building the tree, all courses without prerequisite courses are counted as courses with 0 prerequisite courses.
So we can regard 0 as a root node, but it can be said that there are many trees. With 0, it is like a forest, isn't it.
(2) The initial value is set to \ (dp[x][1]=s[x]; \), where \ (s \) is used to save the corresponding academic score.
I think so.
(3) The \ (sum \) to calculate the number of nodes must be assigned to \ (1 \) first.
Because there is at least 0 (but virtual).
(4) The equation is \ (dp[x][j]=max(dp[x][j],dp[y][k]+dp[x][j-k]); \).
This is also obvious(
Then it's almost done. Put the code down.
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #define ll long long #define ri register int using namespace std; const int MAXN=310; int n,m,k,s[MAXN],dp[MAXN][MAXN]; struct node{ int pos,sco; }; vector <node> T[MAXN]; int dfs(int x,int fa){ dp[x][1]=s[x]; int sum=1; for(ri i=0;i<T[x].size();i++){ int y=T[x][i].pos; if(y==fa)continue; sum+=dfs(y,x); for(ri j=min(sum,m);j>=0;j--){ for(ri k=0;k<=j-1;k++){ dp[x][j]=max(dp[x][j],dp[y][k]+dp[x][j-k]); } } } return sum; } int main() { ios::sync_with_stdio(false); cin>>n>>m; m++; for(ri i=1;i<=n;i++){ cin>>k>>s[i]; node cur={i,s[i]}; T[k].push_back(cur); } dfs(0,n+1); cout<<dp[0][m]; return 0; }
This problem is not difficult, just note that the capacity is at least \ (2 \) and the allocated capacity is at least \ (1 \).
Note that the output needs to be found circularly.
dp part:
int dfs(int x){ dp[x][1]=out[x]; int sum=1; for(ri i=0;i<T[x].size();i++){ int y=T[x][i]; int tmp=dfs(y); sum+=tmp; for(ri j=min(sum,p);j>=2;j--){ for(ri k=1;k<=min(j-1,tmp);k++){ dp[x][j]=min(dp[x][j],dp[y][k]+dp[x][j-k]-1); } } } return sum; }
Output part:
ans=dp[1][p]; for(ri i=2;i<=n;i++)ans=min(ans,dp[i][p]+1); cout<<ans;
This problem needs a foreshadowing: P1510 Jingwei reclamation
You can learn from the idea of Jingwei reclamation and you will do this problem (really, really)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #define ll long long #define ri register int using namespace std; const int MAXN=3010; int n,m,k,a,c,pay[MAXN],dp[MAXN][MAXN]; struct node{ int pos,cos; }; vector <node> T[MAXN]; int dfs(int x){ dp[x][0]=0; if(x>n-m){ dp[x][1]=pay[x]; return 1; } int sum=0; for(ri i=0;i<T[x].size();i++){ int y=T[x][i].pos; int tmp=dfs(y); sum+=tmp; for(ri j=sum;j>=0;j--){ for(ri k=0;k<=tmp;k++){ dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[y][k]-T[x][i].cos); } } } return sum; } int main() { ios::sync_with_stdio(false); memset(dp,0xcf,sizeof(dp)); cin>>n>>m; for(ri i=1;i<=n-m;i++){ cin>>k; for(ri j=1;j<=k;j++){ cin>>a>>c; node cur={a,c}; T[i].push_back(cur); } } for(ri i=n-m+1;i<=n;i++)cin>>pay[i]; dfs(1); for(ri i=m;i>=0;i--){ if(dp[1][i]>=0){ cout<<i; return 0; } } cout<<0; return 0; }
Almost. jpg