状态压缩学习笔记

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

前置技能

1.枚举 SSS 的子集:

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.枚举包含 SSS 的集合:

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

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

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

3.枚举 SSS 中的 111 :

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

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
}

其实就是利用了 lowbitlowbitlowbit 的思想,脑补一下应该都会。

4.其他进制:

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

类推的话,对于 ppp 进制:

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位上的数字
}

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

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

5.判断 ststst 是否是 SSS 的子集:

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

注意位运算优先级。

例题

待填。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值