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