【问题标题】:How does subsets of subsets iteration work?子集迭代的子集如何工作?
【发布时间】:2018-01-13 17:07:32
【问题描述】:

我读了
for ( x = y; x > 0; x = ( y & (x-1) ) )

生成位掩码 y 的所有子集。

这个迭代是如何工作的?有什么直观的解释吗?

来源:http://codeforces.com/blog/entry/45223

请参阅次优解决方案部分。

【问题讨论】:

  • 纸和铅笔。从四五位开始。
  • 我看不到逻辑......我只能看到它有效。这就是我寻求帮助的原因
  • 您熟悉从 11...11 到 00...00 的常用二进制递减吗?所描述的方法本质上是相同的。
  • 我能感觉到它的相似之处,但困扰我的是这个神奇的x = ( y & (x-1) ) 我无法理解它

标签: algorithm bit-manipulation bitmask


【解决方案1】:

直觉: 作为一个数字,位掩码y 不能有多个y 子集。因此,通过倒计时x,您可以保证通过位掩码命中y 的每个子集。但这会产生很多重复。想想1101。如果您从那开始倒计时并使用y 进行掩码,则序列将继续。 110111001001100010011000 等等。通过将屏蔽操作的结果分配给x,您可以跳到它的最后一次出现。

证明:这导致了一个简单的归纳证明。显然,对于长度为 1 的位串,此过程有效。仅有的两个子集10 按此顺序发出。

现在假设这个过程适用于长度为N 的位串。假设Z 是长度为N 的位串。如果您创建位串0Z,那么您将遵循与Z 相同的顺序,因为减法永远不会打开高阶位。如果您创建位串1Z,则会发生以下情况:对于第一个2^nnz(Z) 步骤,将遵循原始Z 序列,并在前面加上1。对于最后的2^nnz(Z) 步骤,遵循原始的Z 序列,并在前面加上0。由于该过程两次访问较小序列的每个元素,第一次是 1,第二次是 0,因此我们得出结论,该过程发出 1Z 的每个子集。

综合起来,我们看到该过程适用于所有位串。

【讨论】:

  • 对不起。我不需要证明.. 我想看看m & (i-1) 是如何给出位掩码的所有子集的.. 如果位掩码设置了 n 位,那么它将给我 2^n - 1 个子集.. 我不能弄清楚结果如何
【解决方案2】:

这里使用的第一个简单事实是,如果我们取值7(二进制中的111)并开始重复递减它(一直到0),我们将通过二进制表示

111, 110, 101, 100, 011, 010, 001, 000

它以一种相当明显的方式表示原始 3 集的所有可能子集。

第二个事实是,在二进制中“减少x”(“从x 中减去1”)意味着:将x 的所有位从最不重要(最右边)的一位开始反转到留到(包括)x 表示中的第一个 1。 “向左”在这里的意思是“在增加位重要性的方向上”。

例如

00001000 - 1 = 00000111, i.e. we invert the `1000` tail
01010101 - 1 = 01010100, i.e. we invert just the `1` tail
10000000 - 1 = 01111111, i.e. we invert the whole thing
and so on

递减操作“关闭”二进制表示中最低有效的1 位并“打开”它右侧的所有零位。

现在,第三个事实是,在您的情况下,x1 位始终是y1 位的子集,因为我们从x = y 开始并在每次迭代中执行x = (whatever) & y .

当我们执行x - 1 时,我们“关闭”(设置为0x 中的最低1 和“打开”(设置为1)所有0 中的x从最低的1 向右。

当我们在 x = (x - 1) & y 中使用 & y 时,我们“关闭”一些 原始x 中的 y 并“打开” xy 的所有低 原始 位。

此时应该已经很明显了,该操作只是x 的“掩码递减”:通过执行x = (x - 1) & y,我们只需递减x 的值,假设只有被@987654355 掩码的位@ 形成x 的值,而所有其他位只是可忽略的“填充位”。

为了与上面的例子相似,递减7y 的初始值可能看起来像10010100。操作x = (x - 1) & y 会将此值视为某种“分布式 7”(非正式地说)。 x 将通过以下值进行处理

1..1.1.., 1..1.0.., 1..0.1.., 1..0.0.., 0..1.1.., 0..1.0.., 0..0.1.., 0..0.0..

其中. 表示x 的“填充”位,它们并不真正参与这个“掩码减量”操作(实际上它们将是0)。注意与原始示例的相似之处7.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    • 2021-08-31
    • 2019-01-08
    • 1970-01-01
    • 2011-10-07
    • 2015-08-12
    • 2020-05-25
    相关资源
    最近更新 更多