滚动数组详解
滚动数组详解
- 何为滚动数组?
- 滚动数组是如何优化空间的?
- 交替滚动
- 例题:来自某某轮廓线DP的题目
- 自我滚动(~~不如交替~~
- 完结!!!
(
何为滚动数组?
什么是滚动数组?是会唱跳
rap的数组吗?其实滚动数组就是它名字的意思,一直在滚动的数组。更形容的说就像一个滚轮,在一个状态轴向前后滚动。那么滚轮大家都知道,它是一个动态的东西,那么放到代码中,那其实就是一个数组,像一个滚轮一样,不断的向前递进,但是递进的过程中,并不关心我们的状态,只注重结果,换句话说,这个数组只保存结果。
当然,滚动数组只是一种优化手段,通常用来优化我们的DP的空间,偶尔下降点时间复杂度。
滚动数组是如何优化空间的?
上文中提到,滚动数组其实就是一个在动态滚动的数组,它会在滚动的时候,将浪费也就是可以省的空间给省下来。举个例子, d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] ] + a [ i ] dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]]+a[i] dp[i][j]=max(dp[i−1][j],dp[i−1][j−1]]+a[i],我们发现, d p [ i ] [ ] dp[i][ ] dp[i][]只与 d p [ i − 1 ] [ ] dp[i-1][] dp[i−1][]有关,与前面 d p [ i − 2 ] [ ] , d p [ i − 3 ] [ ] . . . dp[i-2][],dp[i-3][]... dp[i−2][],dp[i−3][]...无关,所以滚动数组就可以将它们这些空间省下来。
那么滚动数组该如何操作呢?
可以分为两种交替滚动和自我滚动。
交替滚动
顾名思义,就是两行数组交替的进行滚动: d p [ 2 ] [ i ] , d p [ 0 ] [ i ] 和 d p [ 1 ] [ i ] 互相转移 dp[2][i],dp[0][i]和dp[1][i]互相转移 dp[2][i],dp[0][i]和dp[1][i]互相转移。这种方法的有点是简单,特别简单,只要你学过数组你就会,而且代码十分明了,不容易出错。
那么操作代码该如何写呢?给出一个伪代码:
for (日常枚举)
{交换数组 开始转移
}
如上代码是不是看起来十分简单?那么对于交换数组有两种方法,第一异或,第二直接swap。
好,现在你已经会交替滚动了。
来个例题!!!
例题:来自某某轮廓线DP的题目
题目:HDU-4064
题解:
那么好的,这是一道轮廓线DP的题目,但是我们今天的主题不是轮廓线,而是滚动数组,所以等到下次轮廓线DP的时候再重点说说吧。
先说本题主要做法吧,当然是我们的轮廓线DP,但是在做的时候如果普通的做空间直飙1e8,真的是太难受了。于是我们就要开始优化了。首先用上交 ~ 替 ~ 滚 ~ 动 ~的优化。
那么我们可以这么优化,用异或,高级点叫奇偶转变,(swap的一边去)
异或就是我们的异或符号 ^,
那么我们知道异或是不同为1,相同为0,所以拿一个数去异或1,如果是偶数,秒变奇数;如果是奇数秒变偶数。这是因为奇数末尾肯定为1,偶数末尾肯定为0,那么再异或1,就改变奇偶性了。
操作就是如下:
int cur = 0;
cur ^= 1 //变 1就是变奇数了
cur ^= 1 //变 0就是变偶数了
那么总代码就是可以写成如下样子(热心肠的我把轮廓线的部分也给加上去了)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define m_p(i,j) make_pair(i,j)
#define pb push_back
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
#define fir first
#define sec second
const int eps = 1e-8;
ll POW(int a, int b)
{ll sum = 1;for (int i = 1; i <= b; ++i) sum *= a;return sum;
}
inline int read()
{int X=0; bool flag=1; char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}if(flag) return X;return ~(X-1);
}
inline void write(ll X)
{if(X<0) {X=~(X-1); putchar('-');}if(X>9) write(X/10);putchar(X%10+'0');
}
const int mod = 1e9 + 7;
int n, m;
string MP[15][15];
ll dp[2][(1 << 20)], P;
int cur;
int check(char a)
{if (a == 'C') return 0;if (a == 'R') return 1;return 2;
}
void dfs(int pos, int now_mask, int last_mask, ll sum, char left, int hang)
{if (pos == m + 1){sum = (sum * dp[cur ^ 1][last_mask]) % mod;dp[cur][now_mask] = (dp[cur][now_mask] + sum) % mod;return ; }int tot = 0;int num[10];char one[10], two[10], three[10];for (int i = 0; i < 4; ++i){if (pos != 1 && MP[hang][pos][i] != left) continue;char right = MP[hang][pos][(i + 2) % 4];char up = MP[hang][pos][(i + 1) % 4];char down = MP[hang][pos][(i + 3) % 4];int flag = 1;for (int j = 1; j <= tot; ++j){if(right == one[j] && up == two[j] && down == three[j]){flag = 0;++num[j];break;}}if (flag){one[++tot] = right;two[tot] = up;three[tot] = down;num[tot] = 1;}}for (int i = 1; i <= tot; ++i){int jlast_mask = (last_mask * 3 + check(two[i]));int jnow_mask = (now_mask * 3 + check(three[i]));dfs(pos + 1, jnow_mask, jlast_mask, (sum * num[i]) % mod, one[i], hang);}
}
int main(){n = read(), m = read();for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) cin >> MP[i][j];P = POW(3, m);for (int i = 0; i < P; ++i) dp[0][i] = 1;cur = 0;for (int i = 1; i <= n; ++i){cur ^= 1; //开始交替mem(dp[cur], 0);dfs(1, 0, 0, 1LL, 'z', i);}ll ans = 0;for (int mask = 0; mask < P; ++mask) ans = (ans + dp[cur][mask]) % mod;write(ans); return 0;
}
自我滚动(不如交替
你已经会交替滚动了,开始上难度了----自我滚动
我们发现,其实我们把二维转换为两个一维(反正就0/1,算成俩一维吧)。
但是实际上海能进行优化。
就继续拿上面的 d p [ i ] [ j ] = m a x ( . . . ) dp[i][j] = max(...) dp[i][j]=max(...)接着举例吧。
我们是可以接着优化。
我们发现它可以优化成一维,只需要自己跟以前的自己转移就行了。
但是,注 ~ 意 ~ !!!,若上述的转移在枚举j时,一定要反过来枚举,不然可能错,因为它的结果是由同一个空间得到的,可能会影响答案正确性。
那么给出上述那个转移的代码吧(指dp[i][j] = max(…)那个)
for (int i = 1; i <= n; ++i)
{for (int j = m; j >= 1; --j){dp[j] = max(dp[j], dp[j - 1] + a[i]);}
}
完结!!!
恭喜你已经学会滚动数组了!!!
[撒花✿✿ヽ(°▽°)ノ✿]
相关文章:
滚动数组详解
滚动数组详解 何为滚动数组?滚动数组是如何优化空间的?交替滚动例题:来自某某轮廓线DP的题目 自我滚动(~~不如交替~~ 完结!!! ( 宇宙免责任书:我用的是C) 何为滚动数组? 什么是滚动…...
C 语言动态链表
线性结构->顺序存储->动态链表 一、理论部分 从起源中理解事物,就是从本质上理解事物。 -杜勒鲁奇 动态链表是通过结点(Node)的集合来非连续地存储数据,结点之间通过指针相互连接。 动态链表本身就是一种动态分配内存的…...
【Leetcode】二十、记忆化搜索:零钱兑换
文章目录 1、记忆化搜索2、leetcode509:斐波那契数列3、leetcode322:零钱兑换 1、记忆化搜索 也叫备忘录,即把已经计算过的结果存下来,下次再遇到,就直接取,不用重新计算。目的是以减少重复计算。 以前面提…...
json数据格式 继续学习
1.定义 轻量级的数据交互格式,可以按照json数据格式去组织和封装数据。 本质是一个带有特定格式的字符串。 2.功能 负责不同编程语言中的数据传递和交互。 3.json数据格式转化 """ 演示json数据和python字典之间的转换 """ impor…...
gradle 构建项目添加版本信息
gradle 构建项目添加版本信息,打包使用 spring boot 的打包插件 build.gradle 配置文件 bootJar {manifest {attributes(Project-Name: project.name,Project-Version: project.version,"project-Vendor": "XXX Corp","Built-By": &…...
vue3 学习笔记17 -- 基于el-menu封装菜单
vue3 学习笔记17 – 基于el-menu封装菜单 前提条件:组件创建完成 配置路由 // src/router/index.ts import { createRouter, createWebHashHistory } from vue-router import type { RouteRecordRaw } from vue-router export const Layout () > import(/lay…...
使用 Redis 实现验证码、token 的存储,用自定义拦截器完成用户认证、并使用双重拦截器解决 token 刷新的问题
可以看一下我以前做过的笔记:黑马点评 短信登录部分 基于session实现登录流程 1.发送验证码 用户在提交手机号后,会校验手机号是否合法,如果不合法,则要求用户重新输入手机号 如果手机号合法,后台此时生成对应的验…...
反转链表 - 力扣(LeetCode)C语言
206. 反转链表 - 力扣(LeetCode)( 点击前面链接即可查看题目) /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* reverseList(struct ListNode* head) {if(head NULL)…...
【Linux】进程间通信(1):进程通信概念与匿名管道
人与人之间是如何通信的?举个简单的例子,假如我是月老,我要为素不相识的但又渴望爱情的男女两方牵红线。我需要收集男方的信息告诉女方,收集女方的信息告诉男方,然后由男女双方来决定是否继续。对于他们而言࿰…...
Spring从入门到精通 01
文章目录 1. 依赖注入 (Dependency Injection, DI)2. 面向切面编程 (Aspect-Oriented Programming, AOP)3. 事务管理4. 简化 JDBC 开发5. 集成各种框架和技术6. 模块化和扩展性:主要的 Spring 模块:Core Container:AOP 模块:Data …...
C语言经典习题25
冒泡排序 对一维数组进行升序排序,然后在数组中输入20个数,将排序后的结果打印输出。 #include<stdio.h> #define N 20 int main() {int a[N];int i;for(i0;i<N;i) //初始化数组的数 {scanf("%d",&a);}for(i0;…...
2-47 基于matlab的时域有限差分法(FDTD法)拉夫等效原理进行时谐场外推
基于matlab的时域有限差分法(FDTD法)拉夫等效原理进行时谐场外推。外推边界距离吸收边界的距离、电磁场循环、傅立叶变换提起幅值和相位、各远区剖分点电场、方向系数计算等操作,得出可视化结果。程序已调通,可直接运行。 2-47 时域有限差分法(FDTD法) 拉…...
JupyterNotebook快捷键 自用
COMMAND MODE —————————————————————————————— Up Down cells的上下选择 A B 在上/下方插入cell C V X 复制/粘贴/剪切cell 双击D 删除所选cell Z 恢复被删除的cell 双击I Interrupt中断内核 Shift Enter 运行cell并选择下方 EDIT MODE ———…...
【我的OpenGL学习进阶之旅】讲一讲GL_TEXTURE_2D和GL_TEXTURE_EXTERNAL_OES的区别
在使用OpenGL ES进行图形图像开发时,我们常使用GL_TEXTURE_2D纹理类型,它提供了对标准2D图像的处理能力。这种纹理类型适用于大多数场景,可以用于展示静态贴图、渲染2D图形和进行图像处理等操作。 另外,有时我们需要从Camera或外部视频源读取数据帧并进行处理。这时,我们…...
Makefile 如何将生成的 .o 文件放到指定文件夹
研究了不少文章,我行通了一个,但是也不全,目前只能适用当前文件夹,如果源文件有子文件夹处理不了,还得继续研究。很多人说编译完把O文件移动走或者直接删掉。我想说的是不符合我的要求,移走或者删除O文件&a…...
聊一聊知识图谱结合RAG
因为最近在做一些关于提高公司内部使用的聊天机器人的回答准确率,并且最近微软官方也是开源了一下graphrag的源码,所以想聊一聊这个知识图谱结合rag。 rag在利用私有数据增强大模型回答的领域是一种比较典型的技术,也就是我们提出问题的时候&…...
Java面试锦集 之 一、Java基础(1)
一、Java基础(1) 1.final 关键字的作用? 修饰变量: 一旦被赋值,就不能再被修改,保证了变量值的稳定性。 例: final int NUMBER 10; //之后就不能再改变 NUMBER 的值了。修饰方法:…...
【leetcode】排列序列
给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。 按大小顺序列出所有排列情况,并一一标记,当 n 3 时, 所有排列如下: "123""132""213""231""312""321" 给定…...
【Cesium开发实战】视频融合功能的实现,可自定义位置和视频路径
Cesium有很多很强大的功能,可以在地球上实现很多炫酷的3D效果。今天给大家分享一个视频融合功能。 1.话不多说,先展示 视频融合 2.设计思路 点击绘制开始在地图上绘制视频融合的点位,形成视频播放的区域,双击弹框输入名称和要播放视频的路径,即可对应区域播放对应视频,…...
【秋招笔试题】小明的美食
解析:思维题。由于需要互不相同,每次操作取重复的值与最大值相加即可,这样即可保证相加后不会新增重复的值。因此统计重复值即可。 #include <iostream> #include <algorithm>using namespace std; const int maxn 1e5 5; int…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...
shell脚本质数判断
shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数)shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数) 思路: 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...
