「アルゴリズム コンペティション: クイック 300 問」は 2024 年に出版される予定で、「アルゴリズム コンペティション」の補助問題集です。
すべての質問は、自作の OJ New Online Judgeに配置されます。
コードは C/C++、Java、Python の 3 つの言語で提供されており、トピックは主に中レベルから低レベルのトピックであり、初級レベルから上級レベルの学生に適しています。
「 Pebble Game 」、リンク: http://oj.ecustacm.cn/problem.php?id=1119
質問の説明
【問題の説明】石の山が 2 つあり、2 人が交代で石を拾います。取るたびに大きい方の石からしか取れず、取った数は小さい方の石の数の整数倍でなければならず、最後に石の山を空にできた人の勝ちです。初期の石の数を考慮して、両方の人が最適な戦略を採用した場合、最初のプレイヤーが勝つことができるかどうかを尋ねます。
[入力形式]入力にはほとんどのデータが含まれます。データの各セットには、石の初期数を表す 2 つの正の整数 a と b を含む 1 つの行が含まれています。a、b≦109。入力は 2 つのゼロで終わります。
【出力形式】先手が勝った場合は「勝ち」、勝てなかった場合は「負け」を出力します。
【入力サンプル】
34 12
15 24
0 0
【出力サンプル】
win
lose
答え
a≧bとする。現在空の石を取れた方が勝ちとすると、現在の状況は a=kb、つまり a は b の整数倍である必要があり、空の石を取れた方が勝ちとなります。
最初の例「34, 12」は次のようになります:
A: 34-24, 12 -> 10, 12,
B: 10, 12-10 -> 10, 2, B にはこの
方法: A: 10-10 , 2 -> 0、2、Jia Sheng の
読者は、2 番目の例を自分でシミュレートできます。
さまざまな状況におけるゲームの状況については、以下で説明します。最初は a≧b であると仮定します。
(1) 状況 1: a = b。先手は山を空にすることができるので勝ちます。
(2) 位置 2: b < a < 2b。この位置は先手にとって不利です。 a の山から b を取り、ab を残すしかないからです。新しい 2 つの山は a' = b、b' = ab です。a'≠b' があることに注意してください。ゲームは終了していません。まだ先攻のチャンスがあります。次のステップでもまだ b' <a' < 2b' であれば、不利な状況は相手に移ります。a' ≥ 2b' の場合は、状況 (3) の説明を参照してください。
(3) 位置 3: a≧2b。
a がちょうど b の k 倍である場合 (a = kb)、先行者は直接 a=kb をショートし、先行者が勝ちます。
a が b の倍数でない場合、先手は b の特定の倍数を取得して状況 2 に切り替え、相手を不利な状況に置きながら、後続の状況で自分の番が来たときに有利な状態を維持することができます。
たとえば、a=13、b=5、Aがリードしているので、
A: 13-5, 5 -> 8, 5とすると、次のステップ(8, 5)が2の位置に変わり、Bが不利になります。ポジション
B: 8- 5、5 -> 3、5、B にはこの選択肢しかありません
A: 3、5-3 -> 3、
B: 3-2, 2 -> 1, 2, B には次の選択肢しかありません
A: 1, 2-2 -> 1, 0, A が勝ちます
A が正しい最初の一歩を踏み出さないと失敗につながります:
A: 13-10、5 -> 3、5
B: 3、5-3 -> 3、2、B の選択肢は 1 つだけ
A: 3-2、2 -> 1、2、A の選択肢は 1 つだけ
B: 1、2-2 -> 1、0、B の勝ち
つまり、A には負けるか勝つかの 2 つの選択肢があり、必ず勝つ方を選択します。
上記の話をまとめると、まず勝つための条件は、現在1位と3位にいるということです。
【ポイント】状況分析。
C++ コード
dfs()で試合状況を変換して結果を返します。dfs() の複雑さはどれくらいですか? 6 行目は、b < a < 2b の場合に dfs(ab, b) を実行します。毎回 ab は少なくとも半分に減らされるため、複雑さは O ( loga) O(loga)になります。O(loga)的,当 a = 1 0 9 a=10^9 ある=1 09时, l o g a = 30 loga = 30 ログア_ _ _=30。
#include<bits/stdc++.h>
using namespace std;
bool dfs(int a, int b){
if(a < b) swap(a, b); //保证多的石子在前
if(a >= 2*b || a==b) return true; //当前处于局面1、局面3,获胜
return !dfs(a-b, b); //局面2,对方只能取a-b
}
int main(){
int a, b;
while(cin>>a>>b && (a+b)) {
if(dfs(a, b)) cout<<"win" <<endl;
else cout<<"lose"<<endl;
}
return 0;
}
Javaコード
import java.util.Scanner;
public class Main {
public static boolean dfs(int a, int b) {
if (a < b) {
int temp = a;
a = b;
b = temp;
}
if (a >= 2 * b || a==b) return true;
return !dfs(a - b, b);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int a = sc.nextInt();
int b = sc.nextInt();
if (a == 0 && b == 0) break;
if (dfs(a, b)) System.out.println("win");
else System.out.println("lose");
}
sc.close();
}
}
Pythonコード
def dfs(a, b):
if a < b: a, b = b, a #交换
if a >= 2 * b or a==b: return True
return not dfs(a - b, b)
while True:
a, b = map(int, input().split())
if a == 0 and b == 0: break
if dfs(a, b): print("win")
else: print("lose")