滚动数组的几种写法

当然,原地滚动永远是最优的(比如:经典的背包问题)

滚动数组适用的条件

打个比方,某dp的转移方程如下
f[i][x] = min(f[i-1][a],f[i-2][b],...,f[i-j][k]
i的状态仅仅取决于(i-1,...,i-j)这j个状态,而与更之前的状态无关
那么更之前的状态我们可以不用保存, 只需要保存待转移的状态转移需要的状态
(这里状态指的是某维度,如 i,i-1)
所以,我们必须能够确定转移需要的状态的最大数目,才能使用滚动数组优化

滚动数组的几种写法

特殊情况,只取决于上一个维度的状态
  1. 利用相邻两个数奇偶性不同这一性质 进行转移
    例子:acwing292炮兵阵地的转移方程
    f[i & 1][j][k] = max(f[i & 1][j][k], f[i - 1 & 1][u][j] + cnt[c]);
    利用奇偶性滚动,需要注意我们开始的下标是从奇数还是偶数开始的
  2. 把数组当作变量,交换即可
memcpy(tmp,f[2],sizeof f[2]);
memcpy(f[2],f[1],sizeof f[1]);
memcpy(f[1],tmp,sizeof f[1]);

注:memcpy是对数组元素逐个拷贝的,所以会很慢,此外std::swap()对数组进行交换也是逐个拷贝的,运行效率比memcpy还要慢

当前状态取决于前x个的状态

随着dp的遍历,最后一个状态会变成无用的状态,该状态的空间被拿来重复利用,问题在于如何确定下标,如何减少复杂度
1.取模运算

假设 算上待转移的状态共有x个状态,那么我们用 i mod x得到对应下标(0...x-1)
因为这x个状态是连续的,所以必然可以不重不漏的找到对应下标

2.把数组当成元素,进行交换

末尾的状态 i - x将来用不到,于是把所有状态的值向前平移,腾出位子
不过这样实在是太低效了,又要拷贝元素什么的
但是!! 使用vector就可以避免拷贝.swap对容器和适配器类型是进行交换指针,速度非常快
不过对多维数组的定义比较麻烦
比如自己的某题的定义
vector<vector<vector<int>>>f(2,vector<vector<int>>(1<<M,vector<int>(1<<M,0)));

所以,如果对下标拿捏不定,不如就用vector来搞定。
嫌vector定义太麻烦,就用取模运算咯

点个赞再走? 靓仔

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值