このタイプの質問への最良のアプローチ。
まず、ゲーム理論の基本を理解する必要があります。本当に基本的です。つまり、与えられた数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未満で返される値は異なり、PeterdeRivazのソリューションの値に似ている必要があります。ただし、以下の解決策と一般的なアプローチは問題ありません。
下から上に行く別のアプローチは、次の関数を使用することです。
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)
。このアルゴリズムの複雑さは明らかではありませんが、対数であると思います。