我被问到这个问题:谷歌similar question。在Facebook采访中被问到类似的问题。
确定2/9数字游戏的获胜者
两名玩家玩下面的游戏:他们选择一个随机数N(小于20亿),然后从1开始,轮流将前一轮的数字乘以2或9(他们的选择)。 到达N的人首先获胜。
候选人应该写一个给定N谁决定胜利的函数(第一个或第二个玩家?)
对于乘法工作,基本随机选择2/9还是他们希望我们在移动中添加智能。例如:从乘以2开始,只有当你看到另一个人不能比你更快达到N时才乘以9?
解决这类问题的最佳方法是什么?
答案 0 :(得分:9)
解决此类问题的最佳方法。
首先,你需要对游戏理论有基本的理解。真的很基本。那就是你意识到这样一个事实,即对于一个给定的数字N,对于开始的球员或者对于他的对手的获胜策略,要么存在获胜策略。所以你必须假设他们都知道策略并且尽可能地发挥最佳动作。
然后你开始熟悉游戏。你练习水平较低。你很快就注意到,对于2-9,首发球员是赢球,而对于10-18,他必须输球。因此,您的函数已准备好处理N<=18
。
然后你开始思考一般的制胜战略。知道策略会给你算法。 5分钟后(越快越好)你就会明白你不适合找到获胜策略,因为在这种情况下并不明显。因此,您决定为计算机提供一些基本原则,让它为您解决难题。你知道你会使用递归。
您尝试查找递归规则。您可能希望从结束或从头开始。我将从最后描述这种方法。
游戏的目标是将对手推向区域,在那里他必须给你胜利。而不是自己被推到那个区域。从N / 9到N,有一个获胜区。如果一个人被推到N / 9/2和N / 9之间,他必须输掉。 (因为他的两个动作都会将对手推向胜利区。)所以你写下你的功能:
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);
}
如果你达到了这一点,你就过去了。还有一些细节,比如是否使用float或int,是否使用int向上或向下舍入。但总的来说,你展示了正确的思维方式,并且你已经准备好面对面试官了。)
编辑:实际上上面的代码中有错误。 “获胜”与“能够达到范围(n,2n)”不同。这里可能需要2个函数:wins(n)
和reaches_slightly_above(n)
。后者将以递归方式调用,返回到18以下的值应该不同,类似于Peter de Rivaz解决方案中的值。但是,下面的解决方案和一般方法应该没问题。
替代方法,从下到上,将使用该功能:
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);
}
如果他们要求n
,则返回win(1,n)
的值。这种算法的复杂性并不明显,但我认为它是对数的。
答案 1 :(得分:6)
由于它们必须准确到达N
,因此只有在N
的格式为2^a * 9^b
且a, b
中的一个允许为0时才有可能。{ / p>
在上面找到a
和b
:如果a + b = even
,则第二位玩家将获胜,否则第一位将获胜。
这是因为,在每一步中,玩家都会更接近a
或b
一个,因此更接近a + b
一个。所以问题减少到:给定k
,如果每一步玩家必须从k
中减去1,哪个玩家将首先达到0?
答案 2 :(得分:5)
最佳比赛通常是与对手的移动相反,除了在开始和结束时。
通过与递归解决方案进行比较,结果可以根据数字-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
答案 3 :(得分:3)
无论是试图满足还是达到或超过N
,都可以通过确定在各种情况下总能获胜的策略来解决。我将介绍5个案例(或2个案例,其中第二个案例有4个子案例),涵盖所有N
并为每个案例提供获胜策略。
考虑T = ceil( log(N)/log(18) )
,即T
是最小的权力,18^T
达到或超过N
。
如果18^(T-1) * 9 < N
那么第一个玩家总是输给理想的对手。每当第一个玩家选择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, or 4
。
(k = 1)
第一位玩家获胜。第一个玩家可以以2开始,然后像第二个玩家一样在上面玩,在每个后续转弯中与另一个玩家玩相反的数字直到下一轮。第二个玩家将始终面临初始2的18倍的力量。在18 ^(T-2)* 2时,玩家2最多可以乘以9到18^(T-1)
,这不足以获胜,并且至少可以返回18^(T-2)*4
哪个玩家可以乘以9来赢得18^(T-1)*2
。
(k = 3)
第一位玩家也获胜。这次播放器以9开头并像以前一样播放。第二个玩家将始终面对初始9的18倍的力量。在18 ^(T-2)* 9,玩家2最多可以达到18^(T-2) * 9 * 9 < 18^(T-2) * 18 * 8 = 18^(T-1) * 2^3
,因此不足以赢得,并且可以至少通过乘以2返回18 ^(T-1),玩家一乘以9并获胜。
(k = 2 or 4)
第二位玩家获胜。在这里,第二个玩家应该像以前一样玩相反的数字,直到接近结束,这样每个回合玩家一个以18的力量开始。在18^(T-2)
,玩家一个最多可以到达18^(T-2)* 9 < 18^(T-1)
,所以不够胜利。如果他返回18 ^(T-2)* 9,则玩家2获胜18^(T-2)*9*9 > 18^(T-2)*18*4 = 18^(T-1)*2^2
如果玩家1返回18^(T-2)*2
,则玩家2返回18^(T-2)*4
。然后玩家最多可以制作18^(T-2)*4*9 = 18^(T-1)*2
,这仍然不够。现在玩家1至少可以返回18^(T-2)*8
,这足以让玩家2在18^(T-2)*8*9 = 18^(T-1)*4
之后达到目标。
答案 4 :(得分:2)
是的,你应该考虑两位球员的最佳表现并决定谁将获胜。
在这里,一个简单的递归思维可以引导你找到解决方案。
如果玩家的号码为n
且n*9 >= N
,则当前玩家将赢得游戏。
否则,他会将2*n
或9*n
传递给第二名玩家。
现在,只有当他(2*n
和9*n
)向第二名球员提供的两个选项导致第二名球员的中奖号码时,1st-Player才会输掉比赛,否则他将有机会再次挑选中奖号码。
因此,我们可以编写一个递归方法如下:
因为,游戏中的所有数字都将是格式: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)
,无论1st-Player是否获胜。
答案 5 :(得分:1)
如果N可以除以2和9,并且有一些好的博弈论方法,那么有很好的答案。这是Javascript中一个简单的动态编程方法,可以为任何可能的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;
}
此解决方案的时间复杂度为O(2 * logN)= O(logN)。
答案 6 :(得分:0)
答案(我不是100%肯定):
r = N mod 18
if r belongs to (1,9] player 1 wins
if r belongs to (9,18) or is =1 then player 2 wins.
我没有完整的数学演示,所以我错了。
如果两个玩家(或者至少其中一个)知道如何玩它,这应该是正确的答案。
我能得到这份工作吗? :)
答案 7 :(得分:0)
通过组合博弈论来研究像这样的双人,确定性游戏。这种无聊的博弈论与经济学中流行的Neumann和Nash更有用的博弈论无关。这篇开创性的作品是一本令人愉快的书,名为Conning Ways by Conway,Berlekamp&amp;盖
思。对于任何游戏,要么:
你的游戏是一个特殊情况,一个公正的游戏,其中游戏的状态看起来与两个玩家相同。最好的例子是一个名为Nim的简单火柴游戏。碰巧所有公正的游戏都等同于Nim(这是Sprague Grundy定理),所以所有公正的游戏都可以完全解决。
让我们解决你的游戏。游戏的可能状态是正整数。我们将每个州分类为第二个玩家的胜利(我们将这些游戏标记为零'0'游戏),或者为第一个玩家赢得胜利(我们将这些游戏标记为明星'*'游戏)。
大于或等于N的整数都是零游戏,因为此时游戏结束了。谁移动它已经失去了。
轮到它的玩家可以移动到上面的零位置的状态是明星游戏。因此,整数n,N/9 <= n < N
都是明星游戏 - 获胜的动作是乘以9。
轮到它的玩家别无选择只能移动到星位的状态再次为零位。所以整数n,N/9/2 <= n < N/9
是零位。我们的球员输了。
等等。使用类似的参数,我们最终将所有整数归类为一个。
对于N = 1000说,
概括我们得出彼得的结论https://stackoverflow.com/a/13367642/284795
答案 8 :(得分:0)
有趣的帖子和答案。 我很想提出一种理论强力函数,它使用2/9因子计算所有组合路径,其中N <= 2×10 ^ 12(或尽可能接近)。 我说“理论”因为我假设那种计算能力甚至超过了FB?