树形dp背包问题
  • 板块学术版
  • 楼主XSUYRL
  • 当前回复2
  • 已保存回复3
  • 发布时间2024/1/22 16:42
  • 上次更新2024/1/22 19:43:00
查看原帖
树形dp背包问题
1030670
XSUYRL楼主2024/1/22 16:42

我们常常用链式前向星来写树形dp问题。但是我认为vector数组加上对于子树个数的优化常常会更加简洁好写。(邻接表和邻接矩阵也是可以使用的,但是我感觉vector真的太简单了

P1122是一个无根树形dp的问题,所以要把每一个节点视为根进行遍历。 P1273和P2074本质上是一个题目,都是采用对当前成本的规划。而这三个题目都可以用vector来实现。

具体实现方法如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=305;
const int inf=0x3ffff;

vector<int>E[maxn];//store the son
int dp[maxn][maxn];//dp[i][j]represents the value of i node including j son
int val[maxn];//value of each son( not the edge but can be seen as edge)

//opmitize of time by tracking the excect number of sons 
int dfs(int u,int m){
	dp[u][1]=val[u];
	int sizeu=1,sizev=0;//the son tree size with root u,v
	for(int i=0;i<E[u].size();i++){
		int v=E[u][i];
		sizev=dfs(v,m-1);
		for(int j=m;j>=1;j--)//分组背包 
			for(int k=1;k<=sizev&&k<j;k++)
				dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k]);
		sizeu+=sizev;
	}
	return sizeu;
}

//didn't optimized
//void dfs(int u,int m){
//	dp[u][1]=val[u];
//	for(int i=0;i<E[u].size();i++){
//		int v=E[u][i];
//		dfs(v,m-1);
//		for(int j=m;j>=1;j--){
//			for(int k=1;k<j;k++){
//				dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k]);
//			}
//		}
//	}
//}
int main(){
	int n,m;
	cin>>n>>m;
	m++;//add a super root
	for(int i=1;i<=n;i++){
		int a;	
		cin>>a>>val[i];
		E[a].push_back(i);
	}
	dfs(0,m);
	cout<<dp[0][m]<<endl;
}

好吧但是我不知道这个为什么不需要记忆化,记忆化优化就是加一个bool vis[maxn]的数组去判断是否访问过子节点如果访问过直接返回即可

2024/1/22 16:42
加载中...