将一对整数相等


51

这是受到我在互联网上某个地方看到的数学问题的启发,但不记得在哪里(更新:原始问题是在数学谜语subreddit上找到的,提供了一个证明,如果有可能,还请参见此Math SE帖子),询问证明以下过程是否可以用于任意任意整数对(据我所记得,任何给定的整数对都可以):

给定一对整数j和k,将它们中的一个加倍并将另一个相加,得到一对新的整数,即(j,k)->(j + 1,k * 2)或(j * 2,k + 1)。然后,使用那些整数重复此过程,以使一对整数相等。

这些给定的示例不一定是最佳的,但是显示了如何对正整数,负整数或零整数进行此过程:

(2, 5) -> (3, 10) -> (6, 11) -> (12, 12)

(5, 6) -> (6, 12) -> (7, 24) -> (14, 25) -> (28, 26) -> (56, 27) -> (112, 28) -> (113, 56) -> (226, 57) -> (227, 114) -> (228, 228)

(0, 2) -> (1, 4) -> (2, 5) -> (3, 10) -> (6, 11) -> (12, 12)

(-4, 0) -> (-3, 0) -> (-2, 0) -> (-1, 0) -> (0, 0)

(3, -1) -> (6, 0) -> (12, 1) -> (13, 2) -> (14, 4) -> (15, 8) -> (16, 16)

(-4, -3) -> (-8, -2) -> (-16, -1) -> (-32, 0) -> (-31, 0) -> ... -> (0, 0)

挑战

创建一个给定两个整数的程序,通过重复递增一个整数并加倍另一个整数,输出使这些整数相等所需的步骤列表

技术指标

  • 该解决方案不一定是最优的,但对于任意对,它必须以有限数量的步骤进行求解
  • 输入必须是两个整数

  • 输出可以是任何合理的输出,可以清楚地表示每个步骤的结果整数,例如:

    • 具有两个不同定界符(任何符号,空格等)的字符串,一个用于一对中的每个整数,每个用于一对中的一个
      • 例如,输入j,k:2,5->输出:3,10; 6,11; 12,12
    • 整数列表的列表
      • 例如输入j,k:2,5->输出:[[3,10],[6,11],[12,12]]
  • 如果输入是一对相等的数字,则可以输出任何东西,只要它与其他非平凡答案一致

    • 例如
      • 如果输入[2,5]具有不包含输入对的输出[[3,10],[6,11],[12,12]],则输入[4,4]应该什么也不输出。
      • 如果输入[2,5]具有输出[[2,5],[3,10],[6,11],[12,12]],但确实包含输入对,则输入[4,4]应该输出[[4,4]]。
  • 适用标准IO方法,禁止标准漏洞

  • 这是代码高尔夫球,所以最短答案以字节为单位


13
顺便说一句,这是一个不错的第一个挑战。欢迎来到PPCG!
阿诺尔德

@Arnauld谢谢!同样感谢您指出错误,我手工完成了所有示例,确实应该自己
亲自

输出可以反向吗?例如[(12,12),(6,11),(3,10),(2,5)]输入(2,5)
拉科尼

1
@Laikoni考虑到仍然需要输出所有步骤,我认为这很好
JMigst

1
我将其作为A304027添加到OEIS中。这对货币对(34,23)似乎特别困难。
彼得·卡吉

Answers:


10

JavaScript(ES6),111 90 83字节

f=(a,b,p=q=[],u=[...p,[a,b]])=>a-b?f(...(q=[[a*2,b+1,u],[a+1,b*2,u],...q]).pop()):u

在线尝试!

已评论

f = (                       // f = recursive function taking:
  a, b,                     //   (a, b) = input integers
  p =                       //   p[] = current path
  q = [],                   //   q[] = queue
  u = [...p, [a, b]]        //   u[] = updated path with [a, b] appended to it
) =>                        //
  a - b ?                   // if a is not yet equal to b:
    f(...                   //   recursive call, using spread syntax:
      (q = [                //     prepend the next 2 possible moves in the queue:
        [a * 2, b + 1, u],  //       a * 2, b + 1
        [a + 1, b * 2, u],  //       a + 1, b * 2
        ...q                //
      ]).pop()              //     use the move on the top of the queue
    )                       //   end of recursive call
  :                         // else:
    u                       //   success: return the (updated) path

9

Haskell,70 69字节

f(w@((i,j):_):r)|i==j=w|1<2=f$r++[(i+1,j*2):w,(i*2,j+1):w]
g x=f[[x]]

在线尝试!

一个简单的BFS。在成对列表的列表中跟踪步骤。

g x=f[[x]]                -- start with a single list where the only
                          -- step is the starting pair
f (w@((i,j):_):r) =       -- let w be the first list of steps
                          --     (i,j) the last pair of the first list of steps
                                       ('last' as in last operated on. As we store
                                        the steps in reverse order it's the
                                        first element in the list)
                          --     r all other lists of steps
   i==j=w                 -- if i==j stop and return the first list
   1<2= f                 -- else make a recursive call
          r++             -- where the new input list is r followed by
                          -- the first list extended one time by
          [(i+1,j*2):w,         (i+1,j*2) and one time by
             (i*2,j+1):w]       (i*2,j+1)

7

Python 3中90个 74 72字节

-2个字节感谢Dennis

def f(a,*x):j,k=a[0];return(j==k)*a or f(*x,[(2*j,k+1)]+a,[(j+1,2*k)]+a)

在线尝试!

将输入作为单例列表


不打高尔夫球

def f(a,*x):              # function taking at least one argument
                          # a is the first argument, all other are stored in x
  j, k = a[0]             # get the newest values of the current path
  return (j==k)*a         # if j is equal to k return the current path
                  or      # else ...
   f(                     # continue ...
     *x,                  # with the remaining paths ...
     [(2*j,k+1)]+a        # and split the current path ...
     [(j+1,2*k)]+a        # in two new ones
    ) 

4

Pyth,41个字节

J]]QL,hhb*2ebWt{KehJ=J+tJm+hJ]d,yK_y_K)hJ

在这里尝试

说明

这是非常简单的广度优先搜索。保留可能的序列队列(J),直到获得匹配的对,然后选择下一个序列,坚持每个可能的移动,然后将它们放在队列的末尾。
为了简洁起见,我们定义了一个函数y(使用lambda表达式L)来执行其中一项动作,并将其向前和向后应用。



4

05AB1E25 22 20字节

将双重嵌套列表作为输入,并输出锯齿列表,每个步骤以一个嵌套深度进行。

[ć¤Ë#¤xs>R‚ø`R‚s¸sâ«

在线尝试!

说明

[                      # start a loop
 ć                     # extract the first element of the current list (current path)
  ¤Ë#                  # break if all elements in the head are equal
     ¤xs>              # duplicate one copy of the head and increment another
         R             # reverse the incremented copy
          ‚ø           # zip them together
            `R‚        # reverse the tail of the zipped list
               s¸sâ    # cartesian product with the rest of the current path
                   «   # append to the list of all current paths

4

视网膜,72字节

\d+
*
/\b(_+),\1\b/^+%`(_+),(_+)$
$&;_$&$2¶$=;$1$&_
G`\b(_+),\1\b
_+
$.&

在线尝试!由于一元算术的限制,只有两个测试用例。说明:

\d+
*

转换为一元。

/\b(_+),\1\b/^+

虽然输入不包含一对相同的数字...

%`(_+),(_+)%

...匹配每行的最后一对...

$&;_$&$2¶$=;$1$&_

...并将该行变成两行,后缀以第一个数字加一,第二个加倍,后缀以第一个数字加一,第二个加一。

G`\b(_+),\1\b

与匹配对保持一致。

_+
$.&

转换回十进制。89 88字节无符号十进制算术版本(也适用于0):

/\b(\d+),\1\b/^+%`(\d+),(\d+)$
$&;$.(_$1*),$.(2*$2*)¶$=;$.(2*$1*),$.(_$2*
G`\b(\d+),\1\b

在线尝试!


4

MATL,24字节

`vxG1r/q:"tt1rEk(+]td0=~

运行时间是随机的,但概率为1是有限的。

代码效率很低。需要超过4或5个步骤的输入在在线解释器中很有可能会超时。

在线尝试!

说明

`         % Do...while
  vx      %   Concatenate stack and delete. This clears the stack from contents
          %   of previous iterations   
  G       %   Push input
  1       %   Push 1
  r       %   Push random number uniformly distributed on (0,1)
  /       %   Divide
  q       %   Subtract 1. The result is a random number, t, that has nonzero
          %   probability of being arbitrarily large. Specifically, t is in
          %   the interval (0,1) with probability 1/2; in (1,2) with probability
          %   1/6; ... in (k,k+1) with probability 1/((k+1)*(k+2).
  :       %   Range [1 2 ... floor(t)]
  "       %   For each (that is: do thw following floor(t) times)
    tt    %     Duplicate twice
    1     %     Push 1
    rEk   %     Random number in (0,1), times 2, round down. This produces a 
          %     number i that equals 0 or 1 with probability 1/2
    (     %     Write 1 at entry i. So if the top of the stack is [a b], this
          %     transforms it into either [1 b] or [a 1]
    +     %     Add, element-wise. This gives either [a+1 2*b] or [2*a b+1] 
  ]       %   End for each
  td      %   Duplicate, consecutive difference between the two entries
  0=~     %   Is it not zero? If so, the do...while loop continues with a new
          %   iteration. Normally the code 0=~ could be omitted, because a
          %   nonzero consecutive difference is truthy. But for large t the
          %   numbers a, b may have gone to infinity, and then the consecutive
          %   difference gives NaN
          % End do...while (implicit). Display (implicit)

3

Stax29 26 字节

ä⌠|Tô&cm♂NV↓↔╗╣¢♠╜╒█¡Φ≈ñY@

运行并调试

这是广度优先的搜索。看来还算快。

它需要一个双数组包装的整数对。输出是用空格分隔的值列表。每两个值代表到解决方案路径中的一对。


2

Haskell,95个字节

g s|a:_<-[a|a@((x,y):_)<-s,x==y]=a
g s=g$do a@((x,y):_)<-s;[(x*2,y+1):a,(x+1,y*2):a]
h t=g[[t]]

在线尝试!输出顺序相反,例如h(2,5)yields [(12,12),(6,11),(3,10),(2,5)]


2

红色,142字节

将输入作为Red格式的整数对的双嵌套块(2, 5)->2x5

红色对的列表形式返回结果,例如2x5 3x10 6x11 12x12。包括初始对。

func[c][a: copy[]foreach d c[l: last d if l/1 = l/2[return d]do replace/all{%+ 1x0 * 1x2
%* 2x1 + 0x1}"%""append/only a append copy d l "]f a]

在线尝试!

严格输入:

输入是两个数字,例如 2 5

红色,214字节

func[a b][g: func[c][a: copy[]foreach d c[l: last d if l/1 = l/2[return d]append/only a append copy d l + 1x0 * 1x2
append/only a append copy d l * 2x1 + 0x1]g a]c: copy[]insert/only c reduce[do rejoin[a 'x b]]g c]

在线尝试!

说明:

f: func[a b][                 
g: func[c][                                   ; recursive helper function
  a: copy[]                                   ; an empty block
  foreach d c[                                ; for each block of the input 
    l: last d                                 ; take the last pair
    if l/1 = l/2[return d]                    ; if the numbers are equal, return the block 
    append/only a append copy d l + 1x0 * 1x2 ; in place of each block append two blocks
    append/only a append copy d l * 2x1 + 0x1 ; (j+1, k*2) and (j*2, k+1)
  ]                                           ; using Red's arithmetic on pairs
  g a                                         ; calls the function anew
]
c: copy[]insert/only c reduce[do rejoin[a 'x b]]; prepares a nested block from the input
g c                                           ; calls the recursive function 
]
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.