Tree dp learning notes

Keywords: Notes

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:

1.P1122 maximum subtree sum

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)

3.P2016 strategy game

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.

1.P2015 binary apple tree

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

3.P1272 reconstructed Road

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;

4.P1273 cable TV network

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

Posted by agsparta on Tue, 30 Nov 2021 15:23:11 -0800