GFOJ738:Cource--动态规划练习2 DFS+树形DP


 XJY是一位勇敢的探险家,这一天他来到传说中的小谷围岛寻找宝藏。小谷围岛上有n个村庄和n-1条道路,且任意两个村庄可以相互到达。第i个村庄里有价值为Vi的大秘宝(取走之后就没有啦);对于第i条道路,XJY需要Ti天才能走完。现在XJY有m天的假期时间以供探险,他会从第k个村庄出发,最后回到第k个村庄。问XJY最多能取走价值多少的宝藏? 

dp[i][j]表示第i个节点j天取到的最多宝藏。对i的每个孩子搜索天数:
dp[i][j]=max{ dp[i][j], dp[child][k]+dp[i][j-k-2*T] },   0<=k<=j
注意:j要倒着算。不然后会出现计算重复的情况! 

 

#include <cstdio>
#include <algorithm>
#include <cstring>
#define add(x,y,z) (to[++num]=H[x],H[x]=num,V[num]=y,T[num]=z)
#define For(x) for(int h=H[x],o=V[h],t=T[h]; h; h=to[h],o=V[h],t=T[h])
using namespace std;
int K,n,m,u,ans,v[100],dp[100][205];
int H[100],V[205],T[205],to[205],num;

void dfs(int x,int Fa){
	dp[x][0]=v[x];
	For(x) if (o!=Fa){		//往下,o 为 x 的子节点 
		dfs(o,x);		//先处理处下面所有点的 dp 值 
		for (int j=m; j; j--)	//从 x 出发回到 x 用 j 天 
			for (int k=j-t*2; k>=0; k--)		//t 是 x 到 o 的时间 
				dp[x][j]=max(dp[x][j],dp[x][j-k-t*2]+dp[o][k]);
				// x 之前的子节点得出的最大值与当前子节点更新答案
				// dp[x][j-k-t*2] 意为当前子节点 o 及以下的占 k 天,然后 x 到 o 来回占了 t*2 天 
	}
}

int main(){
	freopen("a.txt","r",stdin);
	while (scanf("%d",&n)!=EOF){	//多组数据
		num=ans=0;
		memset(dp,0,sizeof(dp));
		memset(to,0,sizeof(to));
		memset(H,0,sizeof(H));
		for (int i=1; i<=n; i++) scanf("%d",&v[i]);
		for (int i=1,uu,vv,tt; i<n; i++){
			scanf("%d%d%d",&uu,&vv,&tt);
			add(uu,vv,tt),add(vv,uu,tt);
		}
		scanf("%d%d",&K,&m);
		dfs(K,0);
		for (int i=0; i<=m; i++) printf("%d ",dp[K][i]);printf("\n\n");
		for (int i=0; i<=m; i++) ans=max(dp[K][i],ans);
		printf("%d\n",ans);
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值