Algorithm 《2/9游戏》(Facebook访谈)
有人问我这个问题:在谷歌。在Facebook的采访中也有类似的问题 确定2/9数字游戏的赢家 两名玩家玩以下游戏:他们选择一个随机数N(少于20亿),然后从1开始,轮流将前一回合的数字乘以2或9(他们的选择)。 谁先到达N,谁就赢 候选人应该写一个函数,给定N决定谁赢(第一名还是第二名?) 将一个2/9的基本随机选择用于乘法运算,或者他们希望我们在移动时增加智能。举个例子:只有当你看到对方不能比你更快地到达N时,才开始用2乘以9 回答这类问题的最佳方式是什么?答案(我不是100%确定): 我没有完整的数学演示,所以我可能错了。Algorithm 《2/9游戏》(Facebook访谈),algorithm,math,Algorithm,Math,有人问我这个问题:在谷歌。在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
第一名玩家获胜。第一个玩家可以从2开始,然后像第二个玩家那样玩,在接下来的每一回合中都玩与另一个玩家相反的号码,直到下一轮到最后一轮。第二个玩家将永远面临着18倍于最初2的力量。在18^(T-2)*2时,玩家2最多可以通过乘以9达到(k=1)
,这还不足以获胜,并且至少可以返回18^(T-1)
哪个玩家可以乘以9以18^(T-2)*4
18^(T-1)*2
第一名玩家也获胜。这一次,玩家一以9开始,和以前一样玩。第二个玩家将永远面对18倍于最初9的力量。在18^(T-2)*9时,玩家二最多可以到达(k=3)
,因此不足以获胜,至少可以通过乘以2返回18^(T-1),而玩家一将乘以9获胜18^(T-2)*9*9<18^(T-2)*18*8=18^(T-1)*2^3
第二名玩家获胜。在这里,第二个玩家应该像以前一样玩相反的数字,直到接近尾声,这样每一轮玩家一开始的幂为18。在(k=2或4)
,玩家最多可以到达18^(T-2)
,因此不足以获胜。如果他返回18^(T-2)*9,玩家二以18^(T-2)*9<18^(T-1)
如果玩家一返回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;
}