[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 < ...
随机推荐
- 小米云原生文件存储平台化实践:支撑 AI 训练、大模型、容器平台多项业务
小米作为全球知名的科技巨头公司,已经在数百款产品中广泛应用了 AI 技术,这些产品包括手机.电视.智能音箱.儿童手表和翻译机等.这些 AI 应用主要都是通过小米的深度学习训练平台完成的. 在训练平台的 ...
- gitbook生成静态页面不跳转
gitbook页面不跳转 现在可以在localhost:4000/查看自己的网页了.而且生成的网页存在_book文件夹中,下次点击 _book文件夹中的index.html就能打开网页,内容无更新,就 ...
- 国庆微信头像DIY:轻松打造个性化头像
前言 国庆节马上要到了,今天就教你如何从0到1使用canvas生成国庆风微信头像. 本文包含以下内容: vue3项目搭建,需求分析 canvas合成图片原理 github自动化部署 开发过程遇到的问题 ...
- Ubuntu更新软件的命令
更新软件源 apt-get update 更新升级所有软件 apt-get upgrade 更新某个软件 apt-get upgrade 名 列出可更新的软件 apt list --upgradabl ...
- Insert a scratch project into a ppt (MSPowerPoinT file)在powerpoint中播放Scratch动画
Insert a scratch project into a ppt (MSPowerPoinT file)在powerpoint中播放Scratch动画 Contributed by liu pe ...
- 小提琴图的绘制方法:Python matplotlib实现
本文介绍基于Python中matplotlib模块与seaborn模块,利用多个列表中的数据,绘制小提琴图(Violin Plot)的方法. 小提琴图作为一种将箱型图与核密度图分别所能表达的信 ...
- FFMPEG+SDL简单视频播放器——人脸检测
前言 最近突发奇想,给播放器加上一个人脸检测的功能(事情似乎朝着奇怪的方向发展了,谁家的播放器会需要去检测人脸啊!),主要的目的是为了学习opencv,尝试将ffmpeg和opencv融合在一起使用. ...
- 小景的Dba之路--如何导出0记录表以及数据泵的使用
小景最近在系统压测相关的工作,其中涉及了数据备份导出的操作.今天的问题是:exp命令不会导出0记录表,那么我们探讨下如何导出0记录表以及数据泵的使用. 首先,我们先刨析一下问题现象及原因: 在 Ora ...
- 搞懂闭包JavaScript的GC机制
其实不管什么语言,都有一套垃圾回收机制.为什么要有垃圾回收机制?因为内存,程序运行需要内存,如果没有垃圾回收(循环引用,内存泄漏),那么内存占用就会越来越高,轻点说会影响性能卡顿,严重的直接导致崩溃. ...
- rust程序设计(3)结构体相关概念和疑问
结构体 // 如何定义结构体 struct User { active: bool, username: String, email: String, sign_in_count: u64, } // ...