树形dp题目汇总

详细算法见:https://user.qzone.qq.com/50222268/blog/1503921896

1.题目:https://www.luogu.org/problemnew/show/P2014#sub

如何将普通树变成兄弟二叉树:

无父节点的节点为 n+1

​
for (int i=1; i<=n; ++i) {

        int a, b;

        cin >> a >> b;

        if (a == 0)    a = n + 1;

        score[i] = b;
        brother[i] = child[a];//i节点的兄弟为其父节点a的孩子
        child[a] = i;

}


​

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

struct node
{
	int wei,l,r;
};

const int maxSize=300;
int n,m;
int vis[maxSize+5][maxSize+5],f[maxSize+5][maxSize+5];
node N[maxSize+5];

void dfs(int x,int y)
{
	int i,j;
	
	if (vis[x][y]==1)//防止重复搜 
		return ;
	vis[x][y]=1;
	
	if (x==0 || y==0)
		return ;
	
	dfs(N[x].r,y);	//不选x节点
	f[x][y]=f[N[x].r][y];
	
	for (i=0;i<y;i++)//选x节点 
	{
		dfs(N[x].l,i);	//孩子节点选i个
		dfs(N[x].r,y-i-1);	//兄弟节点选y-i-1个
		f[x][y]=max(f[x][y],f[N[x].l][i]+f[N[x].r][y-i-1]+N[x].wei);
	}
}

int main()
{
	int i,x,y,ans;
	
	freopen("a.txt","r",stdin);
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		if (x==0)
			x=n+1;
		N[i].wei=y;
		N[i].r=N[x].l;
		N[x].l=i;
	}
	
	for (i=1;i<=n;i++)
		dfs(i,m);//从根节点搜起
	ans=0; 
	for (i=1;i<=n;i++)
		ans=max(ans,f[i][m]);
	printf("%d\n",ans);
	
	return 0;
}

2.题目:https://www.luogu.org/problemnew/show/P2015#sub

此题要注意把边权化点权

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

struct node
{
	int wei,y;
};
struct node1
{
	int l,r,wei;
};

const int maxSize=100;
int n,q;
int vis[maxSize+5],visit[maxSize+5][maxSize+5],f[maxSize+5][maxSize+5];
node1 a[maxSize+5];
vector <node> N[maxSize+5];

void read(int x)
{
	int i;
	node n1;
	
	for (i=0;i<N[x].size();i++)
	{
		n1=N[x][i];
		if (vis[n1.y]==1)
			continue;
			
		a[n1.y].wei=n1.wei;//边权变成点权 
		if (a[x].l==0)
			a[x].l=n1.y;
		else
			a[x].r=n1.y;
		
		vis[n1.y]=1;
		read(n1.y);
		vis[n1.y]=0;
	}
}

void dfs(int x,int q)
{
	int i;
	node n1;
	
	if (visit[x][q]==1)
		return ;
	visit[x][q]=1;
	
	if (x==0 || q==0)
		return ;
	for (i=0;i<q;i++)
	{
		dfs(a[x].l,i);
		dfs(a[x].r,q-i-1);
		f[x][q]=max(f[x][q],f[a[x].l][i]+f[a[x].r][q-i-1]+a[x].wei);
	}
}

int main()
{
	int i,x,y,z;
	node n1;
	
	freopen("a.txt","r",stdin);
	scanf("%d%d",&n,&q);
	
	for (i=1;i<n;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		n1.y=y;		n1.wei=z;
		N[x].push_back(n1);
		n1.y=x;
		N[y].push_back(n1);
	}
	memset(vis,0,sizeof(vis));
	memset(visit,0,sizeof(visit));
	vis[1]=1;
	read(1);
//	for (i=1;i<=n;i++)
//		printf("%d %d %d\n",a[i].l,a[i].r,a[i].wei);
	dfs(1,q+1);
	printf("%d\n",f[1][q+1]);
	
	return 0;
}

3.题目:https://www.luogu.org/problemnew/show/P1352#sub

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

struct node
{
	int y,wei;//wei指y的权重 
};

const int maxSize=6000;
vector <node> N[maxSize+5];
int n;
int a[maxSize+5],ru[maxSize+5],vis[maxSize+5],f[maxSize+5][2];
//f 0去 1不去 
void dfs(int x)
{
	int i,f1=0,f0=0;
	node n1;
	
	for (i=0;i<N[x].size();i++)
	{
		n1=N[x][i];
		if (vis[n1.y]==1)
			continue;
			
		vis[n1.y]=1;
		dfs(n1.y);
		vis[n1.y]=0;
		f0+=f[n1.y][1];
		f1+=max(f[n1.y][0],f[n1.y][1]);
	}
	f[x][0]=max(f[x][0],f0+a[x]);
	f[x][1]=max(f[x][1],f1);
}

int main()
{
	int i,x,y,gen;
	node n1;
	
	freopen("a.txt","r",stdin);
	scanf("%d",&n);
	for (i=1;i<=n;i++)
		scanf("%d",&a[i]);
	
	memset(ru,0,sizeof(ru));
	for (i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		n1.y=x;	n1.wei=a[x];
		N[y].push_back(n1);
		ru[x]++;
	}
	for (i=1;i<=n;i++)
	{
		if (ru[i]==0)
		{
			gen=i;
			break;
		}
	}
	
	memset(vis,0,sizeof(vis));
	dfs(gen);
	printf("%d\n",max(f[gen][0],f[gen][1]));
	
	return 0;
}

4.完美服务器

gfoj---course---动态规划2

注意状态转移方程可以化简

写程序时方程不能特判!!!

原因:

1,此方程是递推出来的,所以不能特判

2,若不满足则直接上maxValue,此处maxValue不能过大。。。

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

const int maxSize=10000,maxValue=1000000;
vector <int> N[maxSize+5];
int vis[maxSize+5],f[maxSize+5][3];

void dfs(int x)
{
	int i,y;
	
	for (i=0;i<N[x].size();i++)
	{
		y=N[x][i];
		if (vis[y]==1)
			continue;
		vis[y]=1;
		dfs(y);
		vis[y]=0;
		f[x][0]+=min(f[y][1],f[y][0]);
		f[x][1]+=f[y][2];
	}
		
	for (i=0;i<N[x].size();i++)
	{
		y=N[x][i];
		if (vis[y]==1)
			continue;
		f[x][2]=min(f[x][2],f[y][0]+f[x][1]-f[y][2]);
	}
}

int main()
{
	int i,n,x,y;
	
	freopen("a.txt","r",stdin);
	while (1)
	{
		scanf("%d",&n);
		if (n==-1)
			break;
		if (n==0)
			continue;
		
		for (i=1;i<=n;i++)
			N[i].clear();
		
		for (i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			N[x].push_back(y);
			N[y].push_back(x);
		}
		memset(vis,0,sizeof(vis));
		for (i=1;i<=n;i++)
		{
			f[i][0]=1;
			f[i][1]=0;
			f[i][2]=maxValue;
		}
		vis[1]=1;
		dfs(1);
		printf("%d\n",min(f[1][0],f[1][2]));
	}
	
	
	return 0;
}

5.寻宝:

https://blog.csdn.net/scutbenson/article/details/81738322

6.行动!行动!

https://blog.csdn.net/scutbenson/article/details/81745008

猜你喜欢

转载自blog.csdn.net/scutbenson/article/details/81668111