Algorithm 《2/9游戏》(Facebook访谈)

Algorithm 《2/9游戏》(Facebook访谈),algorithm,math,Algorithm,Math,有人问我这个问题:在谷歌。在Facebook的采访中也有类似的问题 确定2/9数字游戏的赢家 两名玩家玩以下游戏:他们选择一个随机数N(少于20亿),然后从1开始,轮流将前一回合的数字乘以2或9(他们的选择)。 谁先到达N,谁就赢 候选人应该写一个函数,给定N决定谁赢(第一名还是第二名?) 将一个2/9的基本随机选择用于乘法运算,或者他们希望我们在移动时增加智能。举个例子:只有当你看到对方不能比你更快地到达N时,才开始用2乘以9 回答这类问题的最佳方式是什么?答案(我不是100%确定): 我没有

有人问我这个问题:在谷歌。在Facebook的采访中也有类似的问题

确定2/9数字游戏的赢家

两名玩家玩以下游戏:他们选择一个随机数N(少于20亿),然后从1开始,轮流将前一回合的数字乘以2或9(他们的选择)。 谁先到达N,谁就赢

候选人应该写一个函数,给定N决定谁赢(第一名还是第二名?)

将一个2/9的基本随机选择用于乘法运算,或者他们希望我们在移动时增加智能。举个例子:只有当你看到对方不能比你更快地到达N时,才开始用2乘以9

回答这类问题的最佳方式是什么?

答案(我不是100%确定):

我没有完整的数学演示,所以我可能错了。
如果两个玩家(或至少其中一个)都知道如何玩,这应该是正确的答案


我得到这份工作了吗?:)

由于它们必须精确地到达
N
,因此只有
N
的形式为
2^a*9^b
,并且
a、b
中的一个也允许为0时,才有可能达到此目的

找到上面的
a
b
:如果
a+b=偶数
,则第二名玩家将获胜,否则第一名玩家将获胜


这是因为,在每一步中,玩家都会离
a
b
近一步,从而离
a+b
近一步。因此,问题归结为:给定
k
,如果在每一步中玩家必须从
k
中减去1,那么哪个玩家将首先达到0?

无论是否只是试图达到或超过
N
,这都可以通过确定在各种情况下总是获胜的策略来解决。我将介绍5个案例(或2个案例,第二个案例有4个子案例),涵盖所有
N
,并给出每个案例的获胜策略

考虑
T=ceil(log(N)/log(18))
,即让
T
为最小幂,使得
18^T
满足或超过
N

如果
18^(T-1)*9
那么第一个玩家总是输给一个理想的对手。当第一个玩家选择2时,第二个玩家选择9。当第一个选择9时,第二个选择2。这样,第二个玩家的回合总是以18的幂结束。在
T
回合后,第二名玩家获胜。第一名玩家无法在前一轮中获胜,因为乘以9不足以超过
N
(因此也不等于乘以2)

>现在让我们考虑<代码> 18 ^(t-1)*9 >n,选择最小的<代码> k>代码>这样<代码> 18 ^(t-1)* 2 ^ k> n< /代码>。有四种可能性

k=1、2、3或4

  • (k=1)
    第一名玩家获胜。第一个玩家可以从2开始,然后像第二个玩家那样玩,在接下来的每一回合中都玩与另一个玩家相反的号码,直到下一轮到最后一轮。第二个玩家将永远面临着18倍于最初2的力量。在18^(T-2)*2时,玩家2最多可以通过乘以9达到
    18^(T-1)
    ,这还不足以获胜,并且至少可以返回
    18^(T-2)*4
    哪个玩家可以乘以9以
    18^(T-1)*2

  • (k=3)
    第一名玩家也获胜。这一次,玩家一以9开始,和以前一样玩。第二个玩家将永远面对18倍于最初9的力量。在18^(T-2)*9时,玩家二最多可以到达
    18^(T-2)*9*9<18^(T-2)*18*8=18^(T-1)*2^3
    ,因此不足以获胜,至少可以通过乘以2返回18^(T-1),而玩家一将乘以9获胜

  • (k=2或4)
    第二名玩家获胜。在这里,第二个玩家应该像以前一样玩相反的数字,直到接近尾声,这样每一轮玩家一开始的幂为18。在
    18^(T-2)
    ,玩家最多可以到达
    18^(T-2)*9<18^(T-1)
    ,因此不足以获胜。如果他返回18^(T-2)*9,玩家二以
    18^(T-2)*9*9>18^(T-2)*18*4=18^(T-1)*2^2
    如果玩家一返回
    18^(T-2)*2
    ,玩家二返回
    18^(T-2)*4
    。玩家最多可以做出
    18^(T-2)*4*9=18^(T-1)*2
    ,这仍然不够。现在玩家一至少可以返回
    18^(T-2)*8
    ,这足以让玩家二达到目标,因为
    18^(T-2)*8*9=18^(T-1)*4


是的,你应该从两名球员身上想出一个最佳方案,并决定谁将获胜

在这里,一个简单的递归思维可以引导您找到一个解决方案

如果一名玩家的号码为
n
n*9>=n
,则当前玩家将赢得游戏。
否则,他将把
2*n
9*n
传递给第二名玩家。 现在,只有当第一名玩家向第二名玩家提供的两个选项(
2*n
9*n
)导致第二名玩家的中奖号码时,第一名玩家才会输掉比赛,否则他将有机会再次选择中奖号码

因此,我们可以编写如下递归方法:
因为,游戏中的所有数字都是这样的:
2^i*9^j
我们可以写:

 F(i, j) = true; if (2^i * 9^j * 9) >= N
           !(F(i+1, j) && F(i, j+1)); otherwise

解决方案是在
F(0,0)
,无论第一个玩家是否获胜。

最佳的游戏通常是与对手的移动方向相反,除非在开始和结束时正确

通过与递归解决方案进行比较,结果表明,可以根据数字-1的基数18表示中的最高有效位计算答案,如下所示:

def win29(n):
    if n<=9: return True
    n-=1
    while n>=18:
        n = n//18
    return n==1 or 4<=n<=8
def win29(n):
如果n=18:
n=n//18

返回n==1或4这类问题的最佳解决方法

首先你需要有ba
def win29(n):
    if n<=9: return True
    n-=1
    while n>=18:
        n = n//18
    return n==1 or 4<=n<=8
wins(n) {
  // returns 1, if starting player is able to reach
  // the range [n, 2*n) with his move
  if (n<=18) {
    if (n<=9)
      return 1;
    else
      return 0;
  } else {
    // I must push him to the zone between N/9/2 and N/9
    return wins(n/18);
  }
wins(a,n) {
  if (9*a >= n)
    // I win easily
    return 1;
  else
    // if one of my moves pushes the opponent to the zone
    // where he's not able to win, then I win!
    return !wins(2*a, n) || !wins(9*a, n);
}
function getWhoWins(n) {
    if(getWhichPlayerWins(0, 1, n) === 0) {
        console.log("First player wins for " + n);
    } else {
        console.log("Second player wins for " + n);
    }
}

// Returns 0 if first, 1 if 2nd player would win
function getWhichPlayerWins(currentPlayer, currentNumber, targetNumber) {
    if(currentNumber * 9 >= targetNumber) {
        return currentPlayer;
    }
    var nextPlayer = (currentPlayer + 1) % 2;
    if(getWhichPlayerWins(nextPlayer, currentNumber *2, targetNumber) === currentPlayer || getWhichPlayerWins(nextPlayer, currentNumber *9, targetNumber) === currentPlayer) {
        return currentPlayer;
    }
    return nextPlayer;
}