[Luogu 4912 帕秋莉的魔法] 题解报告
算法:DP, 背包,动态规划
简化版题目:
给定 \(n\) 个物品,物品的价值为 \(v_1 - v_n\),物品的体积为 \(w_1 - w_n\)。需要选择一些物品,使它们的体积和为 \(V\) ,同时让他们的价值和最大。需要注意的是,如果先选择了物品 \(i\) ,后选择了物品 \(j\) (\(i < j\)),那么可以额外获得 \(add_{i, j}\) 的价值。
- 题目分析:这道题我用的是刷表法(不知道什么是刷表法的请自查)
首先,这道题明显是一道 01背包 吧(
但是这道题和普通01背包不一样的地方是,当我们选择当前物品是,还需要考虑下一个要选择的是什么物品(因为有可能额外增加价值嘛...毕竟还是想多赚一点)。
所以,我们在 01 背包的 dp 数组基础上多开一维,用来记录当前在选择第几个物品。这样,我们在转移的时候,用 for 循环枚举的时候,就可以清楚的查询到上次使用的魔法是什么了。
设当前要选择第 \(i\) 个魔法,接下来要选的是第 \(j\) 个魔法,在选择 \(i\) 的时候已经用掉了 \(k\) 的背包容积。
转移方程为: \(f_{j, k + w_j} = max(f_{j, k + w_j}, f_{i, k} + v_j + add_{i, j})\)。
代码大概长这个样子(注意这是错误代码 ...)
memset(f, -0x3f, sizeof f);
f[0][0] = 0;
for (int i = 0; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
for (int k = m; k >= 0; k -- )
f[j][k + w[j]] = max(f[j][k + w[j]], f[i][k] + v[j] + add[i][j]);
恭喜你拿到了 50 pts。
为什么呢?不知道你有没有注意到题目的数据范围的绝对值符号...难道魔法咒语的长度还能为负数(对于这点我是真的雾
所以,我们需要在 \(f\) 数组上面加上一个偏移量 \(delta\) (因为数组下标不能为负数嘛)
对于无解输出 -1 的情况,特判掉就可以了。如果每个咒语魔法值都是负的,增加的魔法值 \(add\) 也都取成最小,那么答案最劣就是 ($ -50-50$) \(\times \ 50 = -5000\),也就是说,如果我们的结果小于 -5000,那么可以直接判定为 -1 。
- 参考代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 52, M = 2500;
int v[N], w[N];
int f[N][(M << 1) + 10];
int n, m, add[N][N];
int delta = 2500;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
scanf("%d%d", &w[i], &v[i]);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
scanf("%d", &add[i][j]);
memset(f, -0x3f, sizeof f);
f[0][delta] = 0;
for (int i = 0; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
for (int k = delta << 1; k >= 0; k -- )
f[j][k + w[j]] = max(f[j][k + w[j]], f[i][k] + v[j] + add[i][j]);
int res = -0x3f3f3f3f;
for (int i = 1; i <= n; i ++ )
res = max(res, f[i][m + delta]);
printf("%d\n", (res < -5000 ? -1 : res));
return 0;
}
这样就轻松拿到 rk1 辣
再贴一个拿到 rk2 的填表法代码叭(就当免费赠送了
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 60, M = 2510;
int f[N][M << 1]; // f[i][j] 表示选择第 i 个物品,体积为 v 的价值。
int n, m;
int v[N], w[N], add[N][N];
int delta = 2500;
int main()
{
scanf("%d%d", &n, &m); // n 为物品数量,m 为背包容积
for (int i = 1; i <= n; i ++ )
scanf("%d%d", &v[i], &w[i]);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
scanf("%d", &add[i][j]);
memset(f, -0x3f, sizeof f);
f[0][delta] = 0;
for (int i = 1; i <= n; i ++ ) // 枚举当前要用什么魔法
for (int j = delta + delta; j >= v[i]; j -- ) // 枚举当前剩余咒语长度(容积)
for (int k = 0; k < i; k ++ ) // 枚举上一个使用的是什么魔法
f[i][j] = max(f[i][j], f[k][j - v[i]] + w[i] + add[k][i]);
int res = -0x3f3f3f3f;
for (int i = 1; i <= n; i ++ )
res = max(res, f[i][m + delta]);
printf("%d\n", (res < -5000) ? -1 : res);
return 0;
}
完结撒花✿✿ヽ(°▽°)ノ✿
[Luogu 4912 帕秋莉的魔法] 题解报告的更多相关文章
- [Luogu] P4910 帕秋莉的手环
题目背景 帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里.不仅擅长许多魔法,还每天都会开发出新的魔法.只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦. 她所用的属性魔法,主要是生命和 ...
- 【题解】Luogu P4910 帕秋莉的手环
原题传送门 "连续的两个中至少有1个金的"珂以理解为"不能有两个木相连" 我们考虑一个一个将元素加入手环 设f\([i][0/1]\)表示长度为\(i\)手环末 ...
- P4910 帕秋莉的手环
题目背景 帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里.不仅擅长许多魔法,还每天都会开发出新的魔法.只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦. 她所用的属性魔法,主要是生命和 ...
- 【Cogs2187】帕秋莉的超级多项式(多项式运算)
[Cogs2187]帕秋莉的超级多项式(多项式运算) 题面 Cogs 题解 多项式运算模板题 只提供代码了.. #include<iostream> #include<cstdio& ...
- cogs 998. [東方S2] 帕秋莉·诺蕾姬
二次联通门 : cogs 998. [東方S2] 帕秋莉·诺蕾姬 交上去后发现自己没上榜 就想着加点黑科技 把循环展开一下 结果WA了.. 万恶的姆Q /* cogs 998. [東方S2] 帕秋莉· ...
- P4915 帕秋莉的魔导书(动态开点线段树)
题目背景 帕秋莉有一个巨大的图书馆,里面有数以万计的书,其中大部分为魔导书. 题目描述 魔导书是一种需要钥匙才能看得懂的书,然而只有和书写者同等或更高熟练度的人才能看得见钥匙.因此,每本魔导书都有它自 ...
- 洛谷 P4910 帕秋莉的手环 矩阵乘法+快速幂详解
矩阵快速幂解法: 这是一个类似斐波那契数列的矩乘快速幂,所以推荐大家先做一下下列题目:(会了,差不多就是多倍经验题了) 注:如果你不会矩阵乘法,可以了解一下P3390的题解 P1939 [模板]矩阵加 ...
- [洛谷P4910]帕秋莉的手环
题目大意:有一个$n(n\leqslant10^{18})$个点的环,每个点可以是$0$或$1$,要求相邻点中至少一个$1$,问方案数,多组询问. 题解:先考虑是一条链的情况,令$f_{i,j}$表示 ...
- COGS2187 [HZOI 2015] 帕秋莉的超级多项式
什么都别说了,咱心态已经炸了... question 题目戳这里的说... 其实就是叫你求下面这个式子的导函数: noteskey 其实是道板子题呢~ 刚好给我们弄个多项式合集的说... 各种板子粘贴 ...
- COGS 2189 帕秋莉的超级多项式
放模板啦! 以后打比赛的时候直接复制过来. 说句实话vector的效率真的不怎么样,但是似乎也还行,最主要是……写得比较爽. #include <cstdio> #include < ...
随机推荐
- 入门篇-其之四-字符串String的简单使用
什么是字符串? 在Java编程语言中,字符串用于表示文本数据. 字符串(String)属于引用数据类型,根据String的源码,其头部使用class进行修饰,属于类,即引用数据类型. 字符串的表示 字 ...
- 关于fdisk -l
摘取:https://blog.csdn.net/digitalkee/article/details/104226846 # fdisk -l Disk /dev/hda: 160.0 GB, 16 ...
- ciscn_2019_c_1 题解
main函数如下: int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [rsp+Ch] [rb ...
- React框架的基本运行原理与组件定义方式
React框架的基本运行原理 React的本质是内部维护了一套虚拟DOM树,这个虚拟DOM树就是一棵js对象树,它和真实DOM树是一致的,一一对应的. 当某一个组件的state发生修改时,就会生成一个 ...
- tomcat环境
tomcat环境部署时需要先部署JDK工具: JDK环境: #将上传的jdk包进行解压/并移至Java目录下: tar xf jdk1.8.0_131.tar.gz mkdir -p /usr/jav ...
- Gson替换掉多漏洞的FastJson
添加依赖: <!-- gson --> <dependency> <groupId>com.google.code.gson</groupId> < ...
- 通过HTML和JavaScript实现随机抽取幸运员工
需求描述: 公司经常会要求IT部门做一个随机抽取员工页面,今天我们通过HTML和JavaScript来实现 HTML 结构 首先,我们需要编写 HTML 代码来定义页面结构和元素.下面是 HTML 代 ...
- 【实践篇】一次Paas化热部署实践分享
前言 本文是早些年,Paas化刚刚提出不久时,基于部门内第一次Paas化热部署落地经验所写,主要内容是如何构建一些热部署代码以及一些避雷经验. 一.设计-领域模型设计 1.首先,确定领域服务所属的领域 ...
- logback java动态配置【动态修改日志级别,动态修改appender】(转)
logback 动态配置 写在前面在做java日志之前,强烈建议大家读一下这篇java日志的前世今生,对理清java日志框架很有帮助!1奉上地址: 一个著名的日志系统是怎么设计出来的 然后说一下,为啥 ...
- C# 压缩PDF文件
PDF 文件可以包含文本.图片及各种媒体元素,但如果文件太大则会影响传输效果同时也会占用过多磁盘空间.通过压缩PDF文件,能够有效减小文件大小,从而提高传输效率并节省存储空间.想要通过C#代码快速有效 ...