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

P1064 [NOIP 2006 提高组] 金明的预算方案——依赖背包

背景

弱化版

入题之前,先看看弱化版【开心的金明】

对于这道题,比平常所作的01背包多了一个重要度。
但仔细想想,背包问题主要是考虑价值与空间的比值(即性价比)。
只需将原物品价值乘以重要度即可。
d p [ j ] = m a x ( d p [ j ] , d p [ j − 价值 ] + 贡献 ) dp[j]=max(dp[j],dp[j−价值]+贡献) dp[j]=max(dp[j],dp[j价值]+贡献)

弱化Code

Code ED:

//算法:01背包
//时间复杂度:O(n^2)
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int N = 5e5+9;struct Node{int t,v;
}g[N];
int n,m;
int dp[N];signed main(void){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);cin >> n >> m;for(int i = 1; i <= m; ++i){cin >> g[i].t >> g[i].v;g[i].v = g[i].t*g[i].v;}for(int i = 1; i <= m; ++i){for(int j = n; j >= 0; --j){if(j >= g[i].t)dp[j] = max(dp[j], dp[j-g[i].t]+g[i].v);}}cout << dp[n] << "\n";return 0;
}

强化版

现在入题【金明的预算方案】

题目大意

又多了一对关系:主件与附件。

主件可以单独购买,附件需要购买相应的主件后才开放购买。
0对应主件,其它数字对应是附件所对应的主件编号(注意:别被题目样例中只有0和1误导,附件对应数字不为0但对应所对应的主件编号。因为我被这绕了十分钟)。

问题主要是考虑对主件与附件进行区分和计算

所以这道题本质上仍是01背包,不过多了些依赖关系,即为依赖背包

变量存储

考虑主件与附件的对应关系,需要对他们进行编号。

使用一结构体方便些。

定义id为其编号,v为其价值,s为其总贡献,f为对应编号值(也可视为判断主附件)。

当然,我们仍需记录各项元素原数值。

定义n,m,v,p,q;为总钱数、空间、原价值、重要度和编号值。
再定义f[N]记录编号值,动转数组dp[N]。

变量命名
struct Node{int id,v,s,f;//编号、价值、总贡献、主附件判断
}g[N];
int n,m,v,p,q;
int f[N],dp[N];

判断主附件

因为需要判断主附件,所以它们的各项数值需要分开来记。
之前定义的q就可以判断(为0为主件,其它为附件)
这里:

if(q == 0)  g[i].id = i, g[i].v = v, g[i].s = v*p, g[i].f = 0;else  g[i].id = q, g[i].v = v, g[i].s = v*p, g[i].f = ++f[q];
编号排序

编号嘛,自然要排好序才好做。
直接利用结构体id编号即可。

bool sort1(Node a, Node b){//编号排序sort1函数if(a.id == b.id)  return a.f < b.f;return a.id < b.id;
}

样例

存储已经完毕,剩下的便是转移方程咯。
先手玩几把样例(必应之举)。

1000 5
800 2 0  买这个,还剩200,贡献为800*2 = 1600
400 5 1  依赖1号物品
300 5 1  依赖1号物品
400 3 0  买这个,还剩600,贡献为400*3 = 1200
500 2 0  买这个,还剩500,贡献为500*2 = 1000
小贴士

(别把贡献当价格买,不然啥也买不起)
玩完#1样例后,发现买4、5号主件最值(1000+1200 = 2200)。

推理一下:那是不是存在部分数据,只选主件?
答案是肯定的。

购买情况

(不试你也行啊,DP肯定多情况啊,OI赛制是让你玩的?)

简单的动转方程: d p [ j ] = m a x ( d p [ j ] , d p [ j − 组合价格 ] + 组合价值 ) dp[j]=max(dp[j],dp[j−组合价格]+组合价值) dp[j]=max(dp[j],dp[j组合价格]+组合价值)
所以综合题目分析来看,存在以下四种情况:

{ 只买主件 : m a x ( d p [ j ] , d p [ j − g [ i ] . v ] + g [ i ] . s ) 买主件和第一种附件 : m a x ( d p [ j ] , d p [ j − g [ i ] . v − g [ i + 1 ] . v ] + g [ i ] . s + g [ i + 1 ] . s ) 买主件和第二种附件 : m a x ( d p [ j ] , d p [ j − g [ i ] . v − g [ i + 2 ] . v ] + g [ i ] . s + g [ i + 2 ] . s ) 三件都买 : m a x ( d p [ j ] , d p [ j − g [ i ] . v − g [ i + 1 ] . v − g [ i + 2 ] . v ] + g [ i ] . s + g [ i + 1 ] . s + g [ i + 2 ] . s ) \begin{cases} 只买主件:max(dp[j], dp[j-g[i].v]+g[i].s)\\ 买主件和第一种附件:max(dp[j], dp[j-g[i].v-g[i+1].v]+g[i].s+g[i+1].s)\\ 买主件和第二种附件:max(dp[j], dp[j-g[i].v-g[i+2].v]+g[i].s+g[i+2].s)\\ 三件都买:max(dp[j], dp[j-g[i].v-g[i+1].v-g[i+2].v]+g[i].s+g[i+1].s+g[i+2].s) \end{cases} 只买主件:max(dp[j],dp[jg[i].v]+g[i].s)买主件和第一种附件:max(dp[j],dp[jg[i].vg[i+1].v]+g[i].s+g[i+1].s)买主件和第二种附件:max(dp[j],dp[jg[i].vg[i+2].v]+g[i].s+g[i+2].s)三件都买:max(dp[j],dp[jg[i].vg[i+1].vg[i+2].v]+g[i].s+g[i+1].s+g[i+2].s)

强化Code

if条件得加附件编号对应主件编号,具体看代码吧。

Code ED:

//算法:依赖背包
//时间复杂度:O(n^2)
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int N = 4e5+10;struct Node{int id,v,s,f;//编号、价值、总贡献、主附件判断
}g[N];
int n,m,v,p,q;
int f[N],dp[N];bool sort1(Node a, Node b){//编号排序sort1函数if(a.id == b.id)  return a.f < b.f;return a.id < b.id;
}signed main(void){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);cin >> n >> m;for(int i = 1; i <= m; ++i){cin >> v >> p >> q;if(q == 0)  g[i].id = i, g[i].v = v, g[i].s = v*p, g[i].f = 0;else  g[i].id = q, g[i].v = v, g[i].s = v*p, g[i].f = ++f[q];}sort(g+1, g+m+1, sort1);//进行编号排序for(int i = 1; i <= m; ++i){if(g[i].f)  continue;for(int j = n; j >= g[i].v; --j){dp[j] = max(dp[j], dp[j-g[i].v]+g[i].s);//记录原始最大值(即只买主件)if(g[i+1].id == g[i].id  &&  j >= (g[i].v+g[i+1].v))//买第一个附件dp[j] = max(dp[j], dp[j-g[i].v-g[i+1].v]+g[i].s+g[i+1].s);if(g[i+2].id == g[i].id  &&  j >= (g[i].v+g[i+2].v))//买第二个附件dp[j] = max(dp[j], dp[j-g[i].v-g[i+2].v]+g[i].s+g[i+2].s);if(g[i+2].id == g[i].id  &&  j >= (g[i].v+g[i+1].v+g[i+2].v))//俩附件都买dp[j] = max(dp[j], dp[j-g[i].v-g[i+1].v-g[i+2].v]+g[i].s+g[i+1].s+g[i+2].s);//《g[i+1-g[i+2].v].v]》}}cout << dp[n] << "\n";return 0;
}

补充练习

【P1273 有线电视网】

相关文章:

  • k8s热更新-subPath 不支持热更新
  • 界面组件DevExpress WPF中文教程:Grid - 如何识别行和卡片?
  • 数据结构(7)—— 二叉树(1)
  • 微信小程序动态组件加载的应用场景与实现方式
  • 字节开源FlowGram:AI时代可视化工作流新利器
  • 【Axure视频教程】下载和安装Axure汉化包
  • 深度解析Mysql中MVCC的工作机制
  • 内存管理【Linux操作系统】
  • .Net Framework 4/C# 面向对象编程进阶
  • 【2025】通过idea把项目到私有仓库(3)
  • 宏基因组产品升级——微生物菌群木质素降解能力评估!
  • 中科君芯JFG150N40B 40V-N沟道增强模式功率驱动器
  • Go语言依赖管理与版本控制-《Go语言实战指南》
  • [蓝桥杯]最大比例
  • [蓝桥杯]三元组中心问题
  • 如何在mac上安装podman
  • 机器学习监督学习sklearn实战三:八种算法对印第安人糖尿病预测数据进行分类和比较
  • 在WPS中如何启用宏VBA wps.vba.exe下载和安装
  • 归一化 Normalization 技术概述、优化思路
  • 使用cursor 编辑器开发 Vue项目,配置ESlint自动修复脚本,解决代码不规范引起的报错无法运行项目问题
  • 求一个用css写的点击左边导航栏右边显示内容的网站/百度搜索风云排行榜
  • 北京网站高端建设/刚刚北京传来重大消息
  • 连云港网站建设电话/推广关键词如何优化
  • 网站logo怎么做/百度收录技巧
  • 邳州做网站/网络营销方式哪些
  • wordpress创建小工具/关键词优化排名