介绍
假设您获得了n
对象的随机排列。排列被密封在一个盒子中,因此您不知道n!
它是哪种。如果设法将置换应用于n
不同的对象,则可以立即推断出其身份。但是,只允许将置换应用于长度n
二进制矢量,这意味着您必须多次应用置换才能识别它。显然,仅将其应用于n
向量1
就可以完成工作,但是如果您很聪明,则可以使用log(n)
应用程序来完成。但是,该方法的代码将更长。
这是一项实验性挑战,您的分数是代码长度和查询复杂度的组合,这意味着对辅助过程的调用次数。规格有点长,请耐心等待。
任务
您的任务是编写一个命名函数(或最接近的对等函数) f
,该函数使用基于0或基于1的索引作为输入n
,并使用正整数和p
前n
整数的排列作为输入。其输出是排列p
。但是,不允许您p
直接访问排列。您唯一可以做的就是将其应用于任何n
位向量。为此,您应该使用一个辅助函数P
,该函数接受一个置换p
和一个bits向量v
,并返回其p[i]
th坐标包含bit 的置换向量v[i]
。例如:
P([1,2,3,4,0], [1,1,0,0,0]) == [0,1,1,0,0]
您可以将“位”替换为任意两个不同的值,例如3
和-4
,或'a'
和'b'
,并且它们不需要固定,因此可以P
在[-4,3,3,-4]
和[2,2,2,1]
的同一调用中使用两者进行调用f
。的定义P
不会计入您的分数。
计分
解决方案在给定输入上的查询复杂度是它对辅助函数进行的调用次数P
。为了使此度量明确,您的解决方案必须是确定性的。您可以使用伪随机生成的数字,但随后还必须为生成器确定初始种子。
在此存储库中,您将找到一个名为的文件permutations.txt
,该文件包含505个排列,使用从0开始的索引(在从1开始的情况下,增加每个数字),每个长度在5到50之间(含150和150)之间。每个排列都在其自己的行上,并且其编号由空格分隔。您的分数是这些输入的字节数f
+平均查询复杂度。最低分获胜。
额外规则
最好使用带说明的代码,并且不允许出现标准漏洞。特别是,各个位是无法区分的(因此,您不能给Integer
对象提供矢量P
并比较它们的身份),并且该函数P
始终返回一个新矢量,而不是重新安排其输入。您可以自由更改和的名称f
以及P
它们接受参数的顺序。
如果您是第一个使用您的编程语言回答的人,我们强烈建议您包括一个测试工具,其中包括该函数的实现,该实现P
还计算调用它的次数。例如,这是Python 3的工具。
def f(n,p):
pass # Your submission goes here
num_calls = 0
def P(permutation, bit_vector):
global num_calls
num_calls += 1
permuted_vector = [0]*len(bit_vector)
for i in range(len(bit_vector)):
permuted_vector[permutation[i]] = bit_vector[i]
return permuted_vector
num_lines = 0
file_stream = open("permutations.txt")
for line in file_stream:
num_lines += 1
perm = [int(n) for n in line.split()]
guess = f(len(perm), perm)
if guess != perm:
print("Wrong output\n %s\n given for input\n %s"%(str(guess), str(perm)))
break
else:
print("Done. Average query complexity: %g"%(num_calls/num_lines,))
file_stream.close()
在某些语言中,不可能编写这样的工具。最值得注意的是,Haskell不允许纯函数P
记录其被调用的次数。因此,允许您重新实现您的解决方案,使其还计算其查询复杂度,并将其用于工具中。
abaaabababaa
并且-4 3 3 3 -4 3
将是位向量。