获得一个数字的有效方法,不能从任何XORing组合生成

时间:2012-03-07 22:51:32

标签: algorithm xor

如果[0..2 64 ]范围内的任何数字不能由给定集合中的一个或多个数字的任何XOR组合生成,是否有一种有效的方法打印至少一个无法访问的号码,或以信息终止,没有无法访问的号码? 这个问题有名字吗?它是否与另一个问题类似,或者您有任何想法,如何解决?

2 个答案:

答案 0 :(得分:16)

每个数字可以被视为Z / 2上的向量空间(Z / 2)^ 64中的向量。你基本上想知道给定的向量是否跨越整个空间,如果没有,产生一个没有跨越的(除了跨度总是包含零向量 - 如果你真的需要一个或多个,你必须特殊情况) 。这可以通过高斯消除来实现。

在这个特定的向量空间中,高斯消除非常简单。从基础的空集开始。在没有更多数字之前,请执行以下操作。 (1)丢弃所有零的数字。 (2)扫描剩余数字的最低位集合(x的最低位为x & ~(x - 1))并选择设置最低位的数字。 (3)把它放在基础上。 (4)通过使用新的基本元素对其进行异或来更新所有其他数字。没有剩余的数字有这个位或任何低位设置,所以我们在64次迭代后终止。

最后,如果有64个元素,那么子空间就是一切。否则,我们进行的迭代次数少于64次,并略微跳过:没有跨越此位的数字。

对于特殊情况零:当且仅当我们从不丢弃数字(即输入向量是独立的)时,零是一个选项。


超过4位数字的示例

从0110,0011,1001,1010开始。选择0011,因为它设置了1位。基础现在是{0011}。其他载体是{0110,1010,1010};请注意,第一个1010 = 1001 XOR 0011。

选择0110,因为它设置了两位。 Basis现在是{0011,0110}。其他载体是{1100,1100}。

选择1100.基础现在是{0011,0110,1100}。其他载体是{0000}。

扔掉0000.我们完成了。我们跳过了高位,因此1000不在范围内。

答案 1 :(得分:3)

正如说唱音乐指出的那样,您可以将问题视为在向量空间中找到基础。但是,没有必要实际完全解决它,只是为了找到是否可以做,如果没有:给出一个示例值(即二进制向量),不能用提供的集合来描述。

就输入集的大小而言,这可以在O(n ^ 2)中完成。这应该与高斯消除进行比较,其中O(n ^ 3)http://en.wikipedia.org/wiki/Gaussian_elimination

64位完全没问题。使用1000比特以下的示例python代码,其中1000个随机值从0到2 ^ 1000-1的集合大约需要一秒钟。

取代执行高斯消除,它足以找出我们是否可以重写三角形上所有位的矩阵,例如:(对于4位版本:)

 original        triangular
 1110 14         1110 14
 1011 11          111  7
  111  7           11  3
   11  3            1  1
    1  1            0  0

解决方案的工作原理如下:首先,具有相同最高位的所有原始值都放在列表列表中。对于我们的例子:

 [[14,11],[7],[3],[1],[]]

最后一个空条目表示原始列表中没有零。现在,从第一个条目中获取一个值,并将该条目替换为仅包含该数字的列表:

 [[14],[7],[3],[1],[]]

然后将保留数字的xor与向量中正确位置的所有已删除条目一起存储。对于我们的情况,我们有14 ^ 11 = 5所以:

 [[14],[7,5],[3],[1],[]]

诀窍是我们不需要扫描和更新所有其他值,只需要具有相同最高位的值。

现在以同样的方式处理项目7,5。保留7,将7 ^ 5 = 2添加到列表中:

 [[14],[7],[3,2],[1],[]]

现在3,2叶[3]并添加1:

 [[14],[7],[3],[1,1],[]]

并且1,1离开[1]并将0添加到最后一个条目,允许没有设置位的值:

 [[14],[7],[3],[1],[0]]

如果最后向量在每个向量条目中包含至少一个数字(如我们的示例中),则基数是完整的并且任何数字都适合。

这是完整的代码:

# return leading bit index ir -1 for 0.
# example 1 -> 0
# example 9 -> 3
def leadbit(v):
    # there are other ways, yes...
    return len(bin(v))-3 if v else -1

def examinebits(baselist,nbitbuckets):
    # index 1 is least significant bit. 
    # index 0 represent the value 0    
    bitbuckets=[[] for x in range(nbitbuckets+1)]  
    for j in baselist:
        bitbuckets[leadbit(j)+1].append(j)   
    for i in reversed(range(len(bitbuckets))):
        if bitbuckets[i]:
            # leave just the first value of all in bucket i
            bitbuckets[i],newb=[bitbuckets[i][0]],bitbuckets[i][1:]
            # distribute the subleading values into their buckets
            for ni in newb: 
                q=bitbuckets[i][0]^ni
                lb=leadbit(q)+1
                if lb:
                    bitbuckets[lb].append(q)
                else:
                    bitbuckets[0]=[0]
        else:
            v=2**(i-1) if i else 0
            print "bit missing: %d. Impossible value: %s == %d"%(i-1,bin(v),v)
            return (bitbuckets,[i])    
    return (bitbuckets,[])

使用示例:(8位)

import random
nbits=8
basesize=8
topval=int(2**nbits)
# random set of values to try:
basel=[random.randint(0,topval-1) for dummy in range(basesize)]
bl,ii=examinebits(basel,nbits)

bl现在是三角形的值列表,直到无法实现(在这种情况下)。丢失的位(如果有的话)可以在ii [0]中找到。

对于以下尝试的值集:[242, 242, 199, 197, 177, 177, 133, 36]三角形版本为:

base value: 10110001 177
base value:  1110110 118
base value:   100100 36
base value:    10000 16
first missing bit: 3 val: 8
( the below values where not completely processed )
base value:       10 2
base value:        1 1
base value:        0 0

以上列表的印刷方式如下:

for i in range(len(bl)):
    bb=bl[len(bl)-i-1]
    if ii and len(bl)-ii[0] == i:
        print "example missing bit:" ,(ii[0]-1), "val:", 2**(ii[0]-1)
        print "( the below values where not completely processed )"
    if len(bb):
        b=bb[0]
        print ("base value: %"+str(nbits)+"s") %(bin(b)[2:]), b