树的题目与树形dp题目

luogu 1352 没有上司的舞会
地址:https://www.luogu.com.cn/problem/P1352

题解:f[i][0]表示这个点不取的情况下的最优解,那它下面的点是可选可不选的状态,所以它的转移为sum(max(f[j][0],f[j][1])),f[i][1]表示这个点是取的状态,那么它下面一层是不能选的,转移方程为sum(f[j][0])+a[i]

#include
using namespace std;
struct edge{
	int n,o;
}e[15000];
int last[7000],flag[7000],f[7000][2];
int w,n,a[7000],x,y,root,ru[7000];
void add(int x,int y){
	w++;e[w].n=last[x];last[x]=w;e[w].o=y;
}
void dfs(int now){
	flag[now]=1;
	f[now][0]=0;
	f[now][1]=a[now];
	for(int w1=last[now];w1;w1=e[w1].n){
		int y=e[w1].o;
		if(flag[y]==1)continue;
		dfs(y);
		f[now][0]+=max(f[y][0],f[y][1]);
		f[now][1]+=f[y][0];
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<n;i++){
		cin>>x>>y;
		add(y,x);
		ru[x]++;
	}
	for(int i=1;i<=n;i++)
		if(ru[i]==0)root=i;
	dfs(root);
	cout<<max(f[root][0],f[root][1])<<endl;
	return 0;
}

luogu 5536 【XR-3】核心城市
地址:https://www.luogu.com.cn/problem/P5536

题解:从最外面的叶子节点开始,一层层往里去除,直到最后剩下的节点数量为k。
注意去掉的时候要有层次感,一个点去掉的前提是它外围的所有枝条都去除了,不然提前去除会有出错的数据。

#include
using namespace std;
#define N 110000
struct edge{
	int n,o;
}e[210000];
queue<int>q;
int w,last[N],n,m,flag[N],x,y,ru[N],flag1[N],ans,mark;
void add(int x,int y){
	w++;e[w].n=last[x];last[x]=w;e[w].o=y;
}
void dfs(int now,int dist){
	flag1[now]=2;
	ans=max(ans,dist);
	for(int w1=last[now];w1;w1=e[w1].n){
		int y=e[w1].o;
		if(flag1[y]==2)continue;
		if(flag1[y]==1)dfs(y,dist+1);
		else dfs(y,0);
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<n;i++){
		cin>>x>>y;
		add(x,y);
		add(y,x);
		ru[x]++;
		ru[y]++;
	}
	for(int i=1;i<=n;i++)
		if(ru[i]==1)q.push(i),flag[i]=1;
	m=n-m;
	if(m==0){
		cout<<0<<endl;
		return 0;
	}
	for(int i=1;i<=m;i++){
		x=q.front();
		flag1[x]=1;
		q.pop();
		for(int w1=last[x];w1;w1=e[w1].n){
			y=e[w1].o;
		 	if(flag[y]==1)continue;
		 	ru[y]--;
		 	if(ru[y]==1){
		 		flag[y]=1;
		 		q.push(y);
			}
		}
	}
	for(int i=1;i<=n;i++)
		if(flag1[i]==0)mark=i;
	dfs(mark,0);
	cout<<ans<<endl;
	return 0;
}

luogu 2014 [CTSC1997]选课
地址:https://www.luogu.com.cn/problem/P2014

题解:树形dp+背包dp
为了方便处理,将0号结果作为最终的root节点,同时我们选取的数量变为m+1个。
对于每个节点,当处理完它所有儿子节点时,就可以根据它的所有儿子节点对此父亲节点做背包dp。

#include
using namespace std;
struct edge{
	int n,o;
}e[700];
int x,y,n,m,w;
int f[310][310],last[310];
void add(int x,int y){
	w++;e[w].n=last[x];last[x]=w;e[w].o=y;
}
void dp(int now){
	for(int w1=last[now];w1;w1=e[w1].n){
		int y=e[w1].o;
		dp(y);
		for(int i=m+1;i>=1;i--)
			for(int j=1;j<=i;j++)
				f[now][i]=max(f[now][i],f[now][i-j]+f[y][j]);
	}
}
int main(){
	cin>>n>>m;
	memset(f,-42,sizeof(f));
	for(int i=1;i<=n;i++){
		cin>>x>>y;
		add(x,i);
		f[i][1]=y;
	}
	f[0][1]=0;
	dp(0);
	cout<<f[0][m+1]<<endl;
	return 0;
}

你可能感兴趣的:(C++,ACM算法)