枚举N维向量


17

给定正整数k > 1和非负整数i,生成非负整数的k-tuple(或- k维向量)。对于每一个k,从ℕ到ℕ地图ķ必须是双射。也就是说,每个输入i应产生一个不同的元组,并且每个可能的元组必须由某个输入产生i

您可以编写程序或函数,通过STDIN(或最接近的替代方案),命令行参数或函数自变量获取输入,并通过STDOUT(或最接近的替代方案),函数返回值或函数(out)参数输出结果。

您可以对输出使用任何方便,明确的平面列表格式。

您的解决方案不应施加任何人为限制ki但您可以假定它们适合您语言的本机整数大小。至少,您必须支持最大为的值255,即使您的本机整数大小也要小于该值。

对于any 1 < k < 32,您的代码应该会在几秒钟内产生一个结果(当然,如果您的答案由于先前的规则而不能支持那么大,则会相应地调整限制)。这应该是没有问题的:它可能解决这一难题,使得它的作品多达2 128在几秒钟,但上限是存在的,以避免回答这实际上从迭代来找到结果。i < 231i0i

请在您的答案中包括对所选映射的描述,以及为什么该映射是双射的(这不需要是正式证明)。

这是代码高尔夫球,最短的答案(以字节为单位)获胜。

相关挑战

Answers:


5

Pyth,15 12字节

ms+0_%Q>_zdQ

测试套件

我的转换类似于xnor的转换,但以10为底。它的工作方式是将输入解压缩为k个独立的数字:

n = 21003034
k = 3

21003034
 1  3  4    134
2  0  3     203
  0  0        0

这些数字在最右边数字的降序中排序,因此任何数字组的所有排序都是可能的。

代码的工作方式是我们反转输入,然后切掉最后一位0, 1, ... k-1,然后取每k第一位,再次反转,0在开头加a ,然后转换为int。


4

CJam,20个字节

q~({4b2fmd2/z2fb~p}*

该映射是双射的,因为它从该答案 k-1次应用了映射。

程序将输入读取为i k。在CJam解释器中在线尝试。

理念

我们可以通过定义f(i)来构造一个双射映射f:N→N 2

  • i转换为其二进制数字的数组。

  • 前面加上一个0到这个数组,如果有奇数个数字。

  • 对结果数组进行解交织,在此过程中形成新的数组。

  • 将这些数组从2转换为整数。将f 1(i)f 2(i)定义为结果。

为了获得双射映射g:N→N 3,我们可以定义g(n):=(f 1(i),f 1(f 2(i)),f 2(f 2(i)))

要获得双射映射h:N→N 4,我们可以定义h(i):=(g 1(i),g 2(i),f 1(g 3(i)),f 2(g 3( i)))

继续上述过程,我们最终得出了双射映射N→N k

q~      e# Read and evaluate all input. This pushes i and k.
({      e# Do k-1 times:
  4b    e#   Convert the integer on the stack (initially i) to base 4.
  2fmd  e#   Replace each base-4 digit d by d/2 and d%2.
  2/    e#   Split into the chunks [d/2 d%2].
  z     e#   Transpose. This collects all quotients in one array and all
        e#   residues in another one.
  2fb   e#   Convert each array from base 2 to integer.
  ~     e#   Dump both integers on the stack.
  p     e#   Print the topmost one.
}*      e#

xnor的想法还给出了20个字节(如果您打高尔夫球比我做的更好,则更少):(q~2bW%1$Te]/zWf%2fbp相反的输入顺序)
Martin Ender 2015年

3

CJam,18个字节

q~({)2bW%_1#p))b}*

它使用更愚蠢的公式。

在这里尝试

说明

q~          e# Read input.
({          e# Repeat k-1 times:
    )       e# Increment the current integer (initially i), to make it positive.
    2b      e# Convert to binary.
    W%      e# Reverse the binary.
            e# The result can be any non-empty binary string without trailing 0s.
    _1#     e# Find the position of the first 1, or the number of initial 0s.
    p       e# Print.
    )       e# Extract the final bit, which is always 1.
            e# An array that can be any binary string is left in the stack.
    )       e# Increment the 1 to make it 2.
    b       e# Convert the binary string to a number using base 2.
            e# Only the number of initial 0s doesn't affect the result,
            e# which is exactly what is printed before.
}*          e# The final integer is printed automatically when the program ends.

总之,它将一个正整数映射到:

  1. 尾随零的数量。
  2. 删除并反转了尾随零的原始整数,并将其尾随(最初是初始的)1删除了。

3

Python 2,62

lambda z,k:[int('0'+bin(z)[~i:1:-k][::-1],2)for i in range(k)]

这段代码很丑陋,容易打高尔夫,但是想法很简单。

k通过读取k具有不同偏移量的每个th位,将二进制扩展打包为一个。例如,使用k=3,输入357映射到(3,0,7)

101100101 <- 357
  1  0  1 -> 5
 0  0  0  -> 0
1  1  1   -> 7

将数字重新压缩在一起可以将其反向,因此这是双射的。这样做时,应将二进制扩展视为具有无限数量的前导零。


3

J,38 28 27字节

(({.,g^:_1@}.)g=:_ q:>:)~<:

这是一个默认的二进位动词,将ik用作左右参数。使用J.js在线尝试。

理念

我们定义了一个地图˚F:N→Ñ ķF(1):=(α 1,...α k-1个,第1 α ķ。P 2 α K + 1 ... - 1) ,其中⟨p Ñ是质数和i + 1 = p 1的序列 α 1 p 2 α 2 ...

根据基本算术定理,映射g:N→ 克(ⅰ):=(α 1,α 2,...) (的主要因子分解的指数i + 1的是双射)。

由于f(i)=(g 1(i),…g k-1(i),g -1(g k(i),g k + 1(i),…)),因此映射f是双射的好。

                            Left argument: i -- Right argument: k
                         <: Decerement k.
(                      )~   Reverse the order of the arguments and apply the
                            dyadic verb inside the parentheses to k-1 and i.
              g=:            Define a monadic helper verb g:
                     >:       Increment its right argument.
                 _ q:         Calculate the exponents of the prime factorization.
                             (implicit) Apply g to i.
(            )               Apply the dyadic verb inside the parentheses to k-1
                             and (g i).
           }.                 Drop the first k-1 elements of (g i)...
          @                   and...
     g^:_1                    apply the inverse of g to the result.
  {.                          Take the first k-1 elements of (g i).
    ,                         Append the rightmost result to the leftmost one.

为什么您的功能是双射的?
xnor

@xnor至少我的解释中没有,因为我错误地交换了几个索引。我添加了证明草图。
丹尼斯

1

Python 2,72

q=lambda z:z and z%2+2*q(z/4)
g=lambda z,k:1/k*[z]or[q(z)]+g(q(z/2),k-1)

该函数q通过从末尾开始每隔一比特就对二进制数起作用。结果是q(z), q(z>>1)给出了两个数字,其二进制数字间穿插给出z。例如,594分为12和17。

1001010010   <- 594
 0 1 1 0 0   ->  12
1 0 0 0 1    ->  17

这是一个双射,因为我们可以将数字拉回一起以恢复原始数字。

该函数g应用此双射k-1时间,从单个元素扩展到一对,再扩展到三元组,再扩展到k-tuple。每次将最后一个元素扩展为两个元素。通过通过双射将输入映射到一对,将对中的第一个元素用作输出的第一项,然后将函数递归地k-1应用于第二个元素以生成其余项,以递归方式完成此操作。


我意识到我把这种方式变得太复杂了……
xnor 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.