【c++提高1】优化DP专题:状压DP & 倍增优化DP & 环形DP的单调队列优化DP

优化DP专题

这是c++提高的第一讲

大纲

1.状压DP概念
2.例题
3.倍增 & RMQ
4.倍增优化DP
5.环形DP
6.环形DP的单调队列优化

1.状压DP概念

动态规划是解决“多阶段决策最优化问题”的一种算法思想。阶段的划分决定了状态的定义,状态定义的一个重要特性就是要确保**“无后效性”。**
很多DP问题在定义状态的时候,为了确保无后效性,需要在状态中加入多个维度,如果每个维度都用一维数组来表示的话,当维度较多时会导致占用的空间太大。
很多时候状态的维度虽然很多,但是决策非常少,特别的很多时候只有两种决策。例如背包问题中每个物品只有0和1两种决策。对于这种情况,没有必要为每个维度都分配一维空间,而是用一个二进制数来存储所有维度,每个二进制位记录一个维度的决策。这种使用二进制对状态进行压缩的DP,称为状态压缩DP。

2.例题

POJ 2411

思路:

按照行进行阶段划分,对于每一行中的每个格子做决策,某一行的任何一个格子,如果其是一个
竖着的1 * 2长方形的上半部分,那么它会对下一行的决策产生影响,否则其对下一行没有影响。
分别用1和0来表示格子的两种状态,1表示格子是1 * 2长方形的上半部分,0表示其他情况。
可以用一个M位的二进制数来表示每一行的某一行的格子状态。定义状态d(i, j)表示第i行的状态为j时前i行的分隔方案的总数,j是用十进制记录的M位二进制数。

在这里插入图片描述第i-1行的形态k能转移到第i行的形态j,当且仅当:
k和j执行与位运算(&)的结果是0(两行的同一列不能同为1(都是12长方形的上半部分))。
k和j执行或位运算(|)的结果中,连续0的数量都是偶数个(代表横着的1
2的方块)。
为了提升性能,可以预处理出[0, 2^M - 1]中所有满足连续0的数量都是偶数的整数集合S。
状态转移方程:d(i, j) = sum(d(i-1, k)); j & k == 0 && j | k ∈ S
初始化:d(i, j) = 0, d(0, 0) = 1;最终答案为:d(N, 0);
时间复杂度:O(N * 2^M * 2^M) = O(N * 4^M);
代码:

#include <bits/stdc++.h>

using namespace std ;

const int N = 12 ;
long long n , m , dp[N][1 << N] ;
bool ok[1 << N] ;

int main ()
{
   


	while (cin >> n >> m && n)
	{
   
		memset (ok , 0 , sizeof (ok)) ;
		for (int i = 0; i < (1 << m); i++)
		{
   
			bool now = true , odd = true ;
			for (int j = 0; j < m; j++)
			{
   
				if (i & (1 << j)) odd &= now , now = true ;
				else now = ! now ;
			}
			ok[i] = odd & now ;
		}
		memset (dp , 0 , sizeof (dp)) ;
		dp[0][0] = 1 ;
		for (int i = 1; i <= n; i++)
		{
   
			for (int j = 0; j < (1 << m); j++)
			
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

{∞}

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值