状态压缩学习笔记

以下全篇下标都是从 1 1 1 开始,习惯从 0 0 0 开始的自行代换(。

前置技能

1.枚举 S S S 的子集:

for(int st=S;st;st=(st-1)&S)//st为S的非空子集

对于空集需要额外的判断。

如果只枚举非空真子集,写成:

for(int st=S&(S-1);st;st=(st-1)&S)//st为S的非空真子集

注意状态是从大到小枚举的。如果要从小到大枚举状态,把上面的每个枚举的状态压进栈里。

2.枚举包含 S S S 的集合:

C=S^U;for(int st=C;st;st=(st-1)&C)//(st|S)为包含S的集合

其中 U U U 是全集,通常为 ( 1 &lt; &lt; n ) − 1 (1&lt;&lt;n)-1 (1<<n)1

注意上面枚举的集合是不包括 S S S 的。

3.枚举 S S S 中的 1 1 1 :

因为能够状态压缩的 n n n 都很小,一般来说就对于每一位枚举的话也不会超时:

for(int i=1;i<=n;i++)if(S&(1<<i-1))//状态S中第i位为1
or
for(int i=1;i<=n;i++)if(S>>(i-1)&1)//状态S中第i位为1

更快一点的:

for(int i=0;i<n;i++)log[1<<i]=i;
for(int st,i;S;S^=st)
{
	st=S&(-S);i=log[st]+1;
	//状态S中第i位为1
}

其实就是利用了 l o w b i t lowbit lowbit 的思想,脑补一下应该都会。

4.其他进制:

对于二进制中,右移 x x x 表示除以 2 x 2^x 2x,左移 x x x 表示乘以 2 x 2^x 2x

类推的话,对于 p p p 进制:

bit[0]=1;for(int i=1;i<=n;i++)bit[i]=bit[i-1]*p;
//枚举状态S的每一位:
for(int i=1;i<=n;i++)
{
	int j=S/bit[i-1]%p;//j表示S状态中第i位上的数字
}

枚举 p p p 进制下的子集一般用不到(其实我也不会orz)

如果空间大小允许建议把题目当成 2 x 2^x 2x 进制来做(例如把 3 3 3 进制当 4 4 4 进制),因为可以用位运算来提高时间效率。

5.判断 s t st st 是否是 S S S 的子集:

if((s&st)==st)//为1,st即为S子集

注意位运算优先级。

例题

待填。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值