当前位置: 首页 > news >正文

博览会(树形DP)

题目描述

某市正在举行一场大型博览会,博览会有 n 个展馆,每个展馆里有若干个展台。这 n 个展馆以 及它们之间的道路可以看成一棵二叉树,博览会的出入口设在根节点——1 号展馆,小明将从这里 出发乘坐电瓶车到各个展馆参观,并最终回到 1 号展馆出口。
由于路程差异,乘坐电瓶车往返不同展馆间的费用也有所区别。出发时,小明的乘车卡里余额 为 k。他现在想知道,若全程都乘坐电瓶车,他最多能参观多少个展台?
说明:只要小明到达了某个展馆,就会参观该展馆内的所有展台,若多次参观同一个展台不重 复计算。

输入

输入共 n+2 行:
第 1 行为 2 个整数 n、k,用一个空格隔开,表示展馆个数和小明乘车卡初始余额。
第 2 行为 n 个数,用一个空格隔开,表示 1 号至 n 号各展馆的展台数目。
接下来 n 行,每行 4 个数,用一个空格隔开;第 i+2 行 4 个数分别表示展馆 i 左子节点展馆号、 到左子节点展馆的费用、右子节点展馆号、到右子节点展馆的费用。如果子节点展馆号为 0 则表示 没有对应的子节点展馆。

输出

输出共 1 行,1 个整数,表示小明最多能参观的展台数量。

样例输入
10 20
2 8 5 1 10 5 9 9 3 5
2 1 3 2
4 8 5 2
6 2 7 2
8 3 9 6 
0 0 10 2
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
样例输出
39
提示

根据样例数据,可以得到如下展馆二叉树示意图(每个圈内标示了展馆号及展台数):


由图可知,小明沿红色箭号路径,到 1、2、5、3、6、7 这六个展馆参观并返回,往返乘车费用 为 18,参观展台数为 39,为能够实现的最大值。

对于 40%的数据:n≤10;k≤20;
对于 100%的数据:n≤50;k≤100;
所有展馆的展台总数不超过 10^5

思路分析

1.读入数据。展馆个数n,乘车卡初始余额k,exhibition_booth存储各展馆的站台数目,adj[u][1]记录展馆u的左子节点展馆号,fee[u][i]记录展馆 u 到左子节点展馆 i 的费用,adj[u][2]记录展馆u的右子节点展馆号,fee[u][j]记录展馆 u 到右子节点展馆 j 的费用。

2.深度优先搜索遍历二叉树结构,从根节点1开始。

3.dp[u][k]表示到达u节点、花费k元,最多能参观的展台数量。

4.深度优先搜索遍历树结构:

(1)对于节点u,dp[u][0]=exhibition_booth[u]。

(2)如果节点u有左子节点 l :

深搜左子节点 l 。

l_cost为节点u到左子节点l的费用。

将当前节点u的DP状态复制到temp中。temp保存的是未加入左子树时的状态,即只包含当前节点u的展台数。

两层循环: 外层循环:j从总费用上限k递减到0,避免重复使用同一状态(类似于01背包的倒序)。 内层循环:x从0循环到 j - 2*l_cost,x表示在左子树内部使用的费用(注意,这里的费用已经是往返费用,即子树内部边的费用都已经按往返计算)。因为从u到左子树l需要往返费用2*l_cost(去一次,回来一次),所以剩余给左子树的费用不能超过j-2*l_cost。因此x的取值范围是0到j-2*l_cost。

条件判断:如果j - 2*l_cost - x < 0就跳过。

状态转移条件:检查temp[j - 2*l_cost - x]和dp[l][x]这两个状态是否有效:temp[j-2*l_cost-x]表示在未加入左子树时,当前节点u在剩余费用j-2*l_cost-x下的最大展台数;dp[l][x]表示左子树l在费用x下的最大展台数。如果两个状态都是有效的,那么就可以进行转移。

状态转移: 更新dp[u][j]:将当前节点u在剩余费用(j-2*l_cost-x)下的展台数(即temp[j-2*l_cost-x])和左子树在费用x下的展台数(dp[l][x])相加,然后与原来的dp[u][j]比较取最大值。

(3)如果节点u有右子节点 r :

类似处理合并右子树。

5.遍历 j 从0到k,dp[1][j]中最大的即为小明最多能参观的展台数量。

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int INF=1e9;
int n,k,exhibition_booth[51],a,b,c,d,fee[51][51],adj[51][3],ans;
vector<vector<int>>dp(55,vector<int>(105,-INF));
void dfs(int u){dp[u][0]=exhibition_booth[u];int l=adj[u][1];int l_cost=fee[u][l];if(l!=0){dfs(l);vector<int>temp=dp[u];for(int j=k;j>=0;j--){for(int x=0;x<=j-2*l_cost;x++){if(j-2*l_cost-x<0)continue;if(temp[j-2*l_cost-x]!=-INF&&dp[l][x]!=-INF){if(dp[u][j]<temp[j-2*l_cost-x]+dp[l][x]){dp[u][j]=temp[j-2*l_cost-x]+dp[l][x];}}}}}int r=adj[u][2];int r_cost=fee[u][r];if(r!=0){dfs(r);vector<int>temp=dp[u];for(int j=k;j>=0;j--){for(int y=0;y<=j-2*r_cost;y++){if(j-2*r_cost-y<0)continue;if(temp[j-2*r_cost-y]!=-INF&&dp[r][y]!=-INF){if(dp[u][j]<temp[j-2*r_cost-y]+dp[r][y]){dp[u][j]=temp[j-2*r_cost-y]+dp[r][y];}}}}}
}
int main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>k;for(int i=1;i<=n;i++){cin>>exhibition_booth[i];}for(int i=1;i<=n;i++){cin>>a>>b>>c>>d;if(a!=0){adj[i][1]=a;fee[i][a]=b;fee[a][i]=b;}if(c!=0){adj[i][2]=c;fee[i][c]=d;fee[c][i]=d;}}dfs(1);for(int i=0;i<=k;i++){ans=max(ans,dp[1][i]);}cout<<ans;return 0;
}

http://www.xdnf.cn/news/1277551.html

相关文章:

  • 性能解析案例
  • Speaking T2 - Dining Hall to CloseDuring Spring Break
  • 论文复现与分析内容关于一种实用的车对车(V2V)可见光通信(VLC)传播模型
  • 攻击实验(ARP欺骗、MAC洪范、TCP SYN Flood攻击、DNS欺骗、DHCP饿死)
  • Doubletrouble靶机练习
  • Leaflet地图高亮与编辑功能实现
  • Jmeter性能测试之检测服务器CPU/Memory/磁盘IO/网络IO
  • 深度学习-卷积神经网络-AlexNet
  • 【走进Docker的世界】Docker环境搭建
  • 震动马达实现库函数版(STC8)
  • 机器学习——多元线性回归
  • C++移动语义、完美转发及编译器优化零拷贝
  • [创业之路-541]:经营分析会 - 企业的经营分析会,研发负责人负责提供哪些信息?
  • 【RocketMQ 生产者和消费者】- ConsumeMessageOrderlyService 顺序消费消息
  • 不同于传统的简并模分离圆极化天线,基于耦合谐振器的圆极化天线的原理是什么?
  • 如何通过API接口实现批量获取淘宝商品数据?(官方与非官方渠道分享)
  • 代码随想录算法训练营第六十天|图论part10
  • Java 基础编程案例:从输入交互到逻辑处理
  • ATF(TF-A)安全通告 TFV-12(CVE-2024-5660)
  • JDBC的连接过程(超详细)
  • 机器学习——标准化、归一化
  • 从零开始理解百度语音识别API的Python实现
  • nginx 反向代理传递原始域名
  • 前端开发中的常见问题与实战解决方案​
  • PostgreSQL 批量COPY导入优化参数配置
  • GC如何判断对象可以被回收?
  • SpringAI报错:com.github.victools.jsonschema.generator.AnnotationHelper
  • 《设计模式》UML类图
  • Java集合框架、Collection体系的单列集合
  • Elasticsearch QueryDSL 教程