【树形dp】ZOJ-3326-Tree of Tree

这道题和昨晚在CF上做的一道题很像,都是树形dp。刚开始时,我写了个很烂的代码水过了,时间复杂度为O(n^3).不过一看觉得不对了,人家的都是0ms的,于是去网上找题解优化,时间就降为O(n^2)了,终究还是自己太水了……

题目

优化前,300ms:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
template<class T> T Max(T x,T y){return x>y?x:y;}
template<class T> T Min(T x,T y){return x<y?x:y;}
#define N 105
vector<int> v[N];
int m,a[N],dp[N][N];
void dfs(int x,int y)
{
	int i,j,k,z,len;
	dp[x][1]=a[x];
	len=v[x].size();
	for(i=0;i<len;i++)
	{
		z=v[x][i];
		if(y==z)continue;
		dfs(z,x);
		for(j=m;j>0;j--)
			for(k=1;k<=j;k++)
				dp[x][j]=Max(dp[x][j],dp[x][k]+dp[z][j-k]);             //状态转移
	}
}
int main()
{
	//freopen("a.txt","r",stdin);
	int i,n,x,y,ans;
	while(scanf("%d%d",&n,&m)!=EOF)
	{	
		for(i=0;i<n;i++)
		{
			scanf("%d",a+i);
			v[i].clear();
		}
		for(i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			v[x].push_back(y);
			v[y].push_back(x);
		}	
		ans=0;
		for(i=0;i<n;i++)             //这个循环浪费了时间
		{
			memset(dp,0,sizeof(dp));
			dfs(i,-1);
			ans=Max(ans,dp[i][m]);
		}
		printf("%d\n",ans);
	}
	return 0;
}


优化后,0ms:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
template<class T> T Max(T x,T y){return x>y?x:y;}
template<class T> T Min(T x,T y){return x<y?x:y;}
#define N 105
vector<int> v[N];
int m,a[N],dp[N][N];
void dfs(int x,int y)
{
	int i,j,k,z,len;
	dp[x][1]=a[x];
	len=v[x].size();
	for(i=0;i<len;i++)
	{
		z=v[x][i];
		if(y==z)continue;
		dfs(z,x);
		for(j=m;j>0;j--)
			for(k=j;k>0;k--)             //这里是优化最关键的地方,由大到小就可以防止覆盖
				dp[x][j]=Max(dp[x][j],dp[x][k]+dp[z][j-k]);
	}
}
int main()
{
	//freopen("a.txt","r",stdin);
	int i,n,x,y,ans;
	while(scanf("%d%d",&n,&m)!=EOF)
	{	
		for(i=0;i<n;i++)
		{
			scanf("%d",a+i);
			v[i].clear();
		}
		for(i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			v[x].push_back(y);
			v[y].push_back(x);
		}	
		memset(dp,0,sizeof(dp));
		dfs(0,-1);
		ans=0;
		for(i=0;i<n;i++)ans=Max(ans,dp[i][m]);	
		printf("%d\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值