简易状压DP
开头甩定义
借助二进制完成对状态的压缩,从而进行动态规划的过程,我们称之为状态压缩动态规划(简称“状压DP”)
位运算
-
左移右移
左移:左移一位,等价于该数x2
eg. 110<<1 = 1100 (十进制从6变为12)
右移同理
eg. 110>>1 = 11(十进制从6变为3) -
与或非
相信各位OIer应当在普及时就学过位运算了,但本蒟蒻还是要讲
与:按位进行与运算 满足两数同一位都为1时结果为1,否则为0
或:按位进行或运算 满足两数同一位都为0时结果为0,否则为1
非:按位取反 -
简单运算
当我们需要判断或修改二进制数S的第i位时,我们进行以下操作
若判断第i位是否为0 即判断 (S&(1<<i)) 是否为0
若要将第i位设置为1 即 (S|(1<<i)) 即1左移i位于S进行或运算
若要将第i位设置为0 即 (S&~(1<<i)) 即S与只有第i位为0的数进行或运算 -
简单应用
经过上面的学习大家可以发现我们可以用位运算的方法来枚举子集
假设集合A={1,2,3,4,5}
我们可以通过将A中的数编号的方式使其转化为一个二进制数
是不是非常神奇呀
下面我们来康康具体操作
假设我们要表示A的子集B={2,4,5}
二进制数位 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|
二进制值 | 1 | 1 | 0 | 1 | 0 |
子集元素 | 5 | 4 | 0 | 2 | 0 |
这里需要注意的是二进制的数位是从0开始的,所以对应关系不要找错
所以B集合用二进制就可以表示为11010啦!!
那么我们来做个练习
李白打酒 【2014蓝桥杯预赛】
话说大诗人李白,一生好饮。
一天,他提着酒壶,从家里出来,酒壶中有酒两斗。他边走边唱:
无事街上走,提壶去打酒
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白有多少种满足要求的遇到店和花的可能情况
输入
无
正确输出
14
题解:
一道简单的练手题
考虑使用01串表示遇到花或者店,因为最后一个一定是花所以枚举14位01串就OK
代码放送~
#include <bits/stdc++.h>
using namespace std;
int main()
{
int ans=0;
for(int i=0;i<(1<<14);i++)//枚举每种情况
{
int ans1=0,ans2=0;
int num