专题讲座6 树形dp 学习心得

目录

 刷题记录

解析

没有上司的舞会

有线电视网

树形dp换根(二次扫描)


 刷题记录

 ZJNU树形dp - Virtual Judge (vjudge.net)

解析

 树形dp一般形式就两种:
dp[根节点][0/1状态] 

dp[根节点][从子树拿了多少节点]

没有上司的舞会

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define nep(i,r,l) for (int i=r;i>=l;i--)
#define CIO std::ios::sync_with_stdio(false)
using namespace std;
const int N=2e5+5;
int val[N];
int dp[N][2];
int v[N];
vector<int> ve[N];
void dfs(int x,int fa){
	dp[x][0]=0;
	dp[x][1]=val[x];
	for (int i=0;i<ve[x].size();i++){
		dfs(ve[x][i],x);
		int v=ve[x][i];
		dp[x][0]+=max(dp[v][1],dp[v][0]);
		dp[x][1]+=dp[v][0];
	}
}
void work(){
	int n;
	cin>>n;
	rep(i,1,n){
		cin>>val[i];
	} 
	int x,fa;
	rep(i,1,n-1){
		cin>>x>>fa;
		ve[fa].push_back(x);
		v[x]=1;
	}
	int root,ans=0;
	rep(i,1,n){
		if (v[i]==0){
			root=i;
		}
	}
	dfs(root,0);
	cout<<max(dp[root][0],dp[root][1])<<endl;
}
signed main(){
	CIO;
	//int _;cin>>_;while(_--)
	{
		work();
	}
	return 0;
}

有线电视网

树上背包问题

1是根节点,2到n-m是中继器,n-m+1到n是终端。终端有各自的钱,树上边权会消耗钱
,问从根节点能到多少个终端使得钱不亏本。
 


#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define pb push_back 
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define nep(i,r,l) for (int i=r;i>=l;i--)
#define CIO std::ios::sync_with_stdio(false)
using namespace std;
const int N=3e3+5;
int dp[N][N];
struct edge{
	int to,w;
};
int siz[N];
vector<edge> ve[N];
void dfs(int x,int fa){
	if (ve[x].size()==0){
		siz[x]=1;
	}
	for (int i=0;i<ve[x].size();i++){
		int v=ve[x][i].to,w=ve[x][i].w;
		if (v!=fa){
			dfs(v,x);
			siz[x]+=siz[v];
			for (int j=siz[x];j>=1;j--){
				for (int k=1;k<=siz[x];k++){
					dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-w);
				}
			}
		}
	}
}
void work(){
	int n,m;cin>>n>>m;
	rep(i,1,n-m){
		int k;cin>>k;
		int v,w;
		rep(j,1,k){
			cin>>v>>w;
			ve[i].push_back({v,w});
		}
	}
	rep(i,1,n){
		rep(j,1,n){
			dp[i][j]=-21000000;
		}
	}
	rep(i,n-m+1,n){
		cin>>dp[i][1];
	}
	dfs(1,-1);
	nep(i,m,1){
		
		if (dp[1][i]>=0){
			cout<<i<<endl;
			return;
		}
	}
}
signed main(){
	CIO;
	{
		work();
	}
	return 0;
}

树形dp换根(二次扫描)

给定一个 n 个点的树,请求出一个结点,使得以这个结点为根时,所有结点的深度之和
最大。一个结点的深度之定义为该节点到根的简单路径上边的数量。


#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define pb push_back 
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define nep(i,r,l) for (int i=r;i>=l;i--)
#define CIO std::ios::sync_with_stdio(false)
using namespace std;
const int N=1e6+5;
const int inf=2100000000;
struct edge{
	int to,w;
};
int siz[N],dep[N];
int f[N];
int n;
vector<int> ve[N];
void dfs(int x,int fa){
	siz[x]=1;
	dep[x]=dep[fa]+1;
	for (int i=0;i<ve[x].size();i++){
		int v=ve[x][i];
		if (v!=fa){
			dfs(v,x);
			siz[x]+=siz[v];
		}
	}
}
void dfsroot(int x,int fa){//从根往下传递 
	for (int i=0;i<ve[x].size();i++){
		int v=ve[x][i];
		if (v!=fa){
			f[v]=f[x]+n-2*siz[v];
			dfsroot(v,x);
		}
	}
}
void work(){
	cin>>n;
	int u,v;
	rep(i,1,n-1){
		cin>>u>>v;
		ve[u].push_back(v);
		ve[v].push_back(u);
	}
	dep[0]=-1;
	dfs(1,0);
	rep(i,1,n) f[1]+=dep[i];
	dfsroot(1,0);
	int maxdep=-1,maxroot;
	rep(i,1,n){
		if (maxdep<f[i]){
			maxroot=i;
			maxdep=f[i];
		}
	}
	cout<<maxroot<<endl;
}
signed main(){
	CIO;
	{
		work();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁水682

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值