CF1249F Maximum Weight Subset 树形dp

https://www.luogu.com.cn/problem/CF1249F

这题看题解云里雾里的,我自认为我写的比较简单;

dp[x][i]表示以x为根,选中节点离x最近距离为i。(最小深度)

那么如何转移呢?

答案无非就是两种方式构成的,原来子树上就有,两棵树合并而成。于是就有了下面的式子

假设新树为x根,ans[x][min(i+j+1)] =  max(dp[x][i]  + dp[p][j] )   (p 为x的所有儿子)//表示参与合并

                          ans[x][i+1] = max(ans[p][i])//表示答案就在子树上

就是这样了,具体可以看代码。

#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 300+11;
typedef long long ll;
ll INF = 1e10;

vector<int>G[maxn];
ll dp[maxn][maxn];
int n,k;
ll list[maxn];
int dep[maxn];


void add(int x,int y){
	G[x].push_back(y);
}


int dfs(int x,int fa){//感觉就是个背包 
	dep[x] = 1;
	for(int s=0;s<G[x].size();s++){
		int p = G[x][s];
		if(p == fa) continue;
		dfs(p,x);
		for(int i=0;i< maxn-1 ;i++){
			list[i] = dp[x][i];//分离出来避免重复计算 
			dp[x][i] = 0;
		}
		for(int i=0;i<maxn-1;i++){
			for(int j=0;j< maxn-1;j++){
				if(i + j + 1 > k) dp[x][min(i,j+1)] = max(dp[x][min(i,j+1)],list[i] + dp[p][j]);//距离要够远才能和一起 
			}
		}
		
		for(int j=0;j<maxn-1;j++){
			dp[x][j+1] = max(dp[x][j+1],dp[p][j]);
		}
		
		dep[x] = max(dep[p]+1,dep[x]);
		
	}
}
int main(){
	cin>>n>>k;
	
	for(int i=1;i<=n;i++){
		cin>>dp[i][0];
	}
	
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	dfs(1,-1);
	ll ans = 0;
	for(int i=0;i<=dep[1];i++){
		if(dp[1][i] != INF) ans = max(ans,dp[1][i]);
	}
	
	cout<<ans<<endl;
	return 0;
} 

/*
14 4
6 4 1 2 3 3 5 2 2 7 3 6 6 1
13 9
3 12
10 11
14 13
6 7
5 2
8 12
10 14
2 14
6 8
1 9
4 13
8 13

输出14 */

  

寻找真正的热爱
原文地址:https://www.cnblogs.com/lesning/p/13867730.html