【树形DP】愚蠢的矿工

并没有什么用的更新时间

【2019/03/05】 题目及代码更新
【2019/03/07】 题解及标程更新


愚蠢的矿工

【题目描述】

Stupid 家族得知在HYC家的后花园里的中央花坛处,向北走3步,向西走3步,再向北走3步,向东走3步,再向北走6步,向东走3步,向南走12步,再向西走2步( - -||)就能找到宝藏的入口,而且宝藏都是藏在山里的,必须挖出来,于是Stupid家族派狗狗带领矿工队去挖宝藏.(HYC家的宝藏被狗狗挖走后有什么感想?)
这个宝藏的制造者为了掩盖世人耳目,他做的宝藏是没有出口,只有入口,不少建造宝藏的人都死在里面.现在知道宝藏总共有N个分岔口,在分岔口处是有财宝的,每个宝藏点都有一个财富值.狗狗只带了M个人来,而且为了安全起见,在每个分岔口,必须至少留一个人下来,这个留下来的人可以挖宝藏(每个人只能挖一个地方的宝藏),这样才能保证不会迷路,而且这个迷宫有个特点,任意两点间有且只有一条路可通.狗狗为了让他的00开心,决定要尽可能地多挖些宝藏回去.现在狗狗的圈叉电脑不在身旁,只能求救于你了,你要知道,狗狗的终身幸福就在你手上了…(狗狗ps:00,你不能就这样抛弃偶……)

【输入格式】

第1行:两个正整数N,M .N表示宝藏点的个数,M表示狗狗带去的人数(那是一条懒狗,他自己可不做事)。(n<=1000,m<=100)
第2行:N个整数,第i个整数表示第i个宝藏的财富值.(保证|wi|<maxint)
第N+2行:两个非负整数A和B,表示A通向B,当A=0,表示A是入口.(保证A,B<=n)

输出格式

输出狗狗能带回去的宝藏的价值。

【样例输入】

4 3
5 6 2 4
1 2
0 1
2 3
3 4

【样例输出】

13

【题解】

题目难度:★★★★☆
思路:①阅读此题,这一题是树形DP的典型例题
②得知此题输入为多叉树,需把多叉树转为二叉树。读入儿子节点和父亲节点,如果这个父亲节点没有子节点,就把儿子节点变成它的左节点,否则变为它最新子节点的右节点(左儿子右兄弟)
③DP式为f[x][y]=max(f[x][y],f[l[x]][i-1]+v[x]+f[r[x]][y-i]),f[x][y]表示在x节点及它的子节点放y个人的最大价值,l[x]表示x节点的左节点,r[x]表示x节点的右节点,v[x]为x节点的权值,i是循环模拟在x节点及它的子节点放几个人
④先将f数组初始化为-1方便判断出界
⑤DP前把f[x][y]的值初始化为它的右节点(不要问我为什么,应该是因为右兄弟比较多吧

【代码】

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1005,maxm=105;
int n,m,f[maxn][maxm],v[maxn],l[maxn],r[maxn],dis[maxn];
void dp(int x,int y){//dp子程序表示在节点x及它的子节点放y个人
    if (f[x][y]==-1){//如果当前节点没有被计算过
		dp(r[x],y);
		f[x][y]=f[r[x]][y];//初始化为右节点
		for (int i=1;i<=y;++i){//i枚举在节点x及它的子节点放y个人
			dp(r[x],y-i);
			dp(l[x],i-1);
			f[x][y]=max(f[x][y],f[l[x]][i-1]+v[x]+f[r[x]][y-i]);//DP式
		}		  
	}
}
int main(){
	cin>>n>>m;
	for (int i=1;i<=n;++i) cin>>v[i];//v数组储存权值
	for (int i=1;i<=n;++i){
		int x,y;
		cin>>x>>y;
			if (dis[x]==0) l[x]=y;
			else r[dis[x]]=y;
			dis[x]=y;//多叉树转二叉树
	}
	for (int i=1;i<=n;++i)
	  for (int j=1;j<=m;++j) f[i][j]=-1;//初始化(以判断边界)
	dp(l[0],m);//从0(起点)的左节点开始DP
	cout<<f[l[0]][m]<<endl;
}

【相关链接】

rqnojT30

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值