題目鏈接:https://leetcode-cn.com/problems/nim-game/description/
您和您的朋友,兩個人一起玩 Nim游戲:桌子上有一堆石頭,每次你們輪流拿掉 1 到 3 塊石頭。 拿掉最后一塊石頭的人就是勝利者。由您來開局。
你們兩個都是聰明人,相信都有最佳的游戲策略。 請編寫一個函數,來判斷您是否可以在給定的石頭數量的情況下贏得游戲。
比方說,如果堆中有4塊石頭,那么你永遠不會贏得比賽:無論你拿走的是 1塊,2塊 還是 3塊 石頭,最后一塊石頭總是會被你的朋友拿走。
這里做一個抽象,假設一推里面有n個石頭,每次可以取 1-m 個石頭。
顯然,如果n=m+1,那么由於一次最多只能取m個,所以,無論先取者拿走多少個,后取者都能夠一次拿走剩余的物品,后者取勝。這里我們就有一個想法了,假設這個石頭推為 (m+1)的倍數,那么第一個人取k( 1 <= k <= m)個,只要第二個人取 (m+1-k)個石頭,那么必定狀態能回到最初的狀態,m+1個。因為每個人都是很聰明的,取的石頭的個數一定要對自己有利。那么,假設最初石頭推不為 (m+1)的倍數。n=(m+1)r+s,那么第一個人只要取s個石頭必定能獲得勝利,反之,如果s == 0 ,那么第一個人必輸。
即,若n=k*(m+1),則后取着勝,反之,存在先取者獲勝的取法。n%(m+1)==0. 先取者必敗。
AC代碼:
1 public boolean canWinNim(int n) { 2 3 return (n % 4) == 0 ? false : true; 4 }
(擴展):尼姆博弈
題型
尼姆博弈模型,大致上是這樣的:
有3堆各若干個物品,兩個人輪流從某一堆取任意多的物品,規定每次至少取1個,多者不限,最后取光者得勝。
獲勝情況對先取者的討論
異或結果為0,先取者必敗,無獲勝方法。后取者獲勝;
結果不為0,先取者有獲勝的取法。
拓展
任給N堆石子,兩人輪流從任一堆中任取(每次只能取自一堆),取最后一顆石子的人獲勝,問先取的人如何獲勝?
根據上面所述,N個數異或即可。如果開始的時候T=0,那么先取者必敗,如果開始的時候T>0,那么只要每次取出石子使得T=0,即先取者有獲勝的方法。
最后一個奇異局勢是(0,0...,0)。另一個奇異局勢是(n,n,0...0),只要對手總是和我拿走一樣多的物品,最后會面對(0,0...,0)。
SG函數模板:
1 import java.util.Arrays; 2 3 class Main { 4 // N 表示可以取的個數 5 // MAXN表示每堆石頭的最大數 6 public static final int N = 20; 7 public static final int MAXN = 1000; 8 public static int[] f = new int[N]; 9 public static int[] SG = new int[MAXN + 10]; 10 public static int[] S = new int[MAXN + 10]; 11 12 public static void main(String[] args) { 13 14 15 } 16 17 void getSg(int n) { 18 int i, j; 19 Arrays.fill(SG, 0); 20 for (i = 1; i <= n; i++) { 21 Arrays.fill(S, 0); 22 for (j = 0; f[j] <= i && j < N; j++) 23 S[SG[i - f[j]]] = 1; 24 for (j = 0;; j++) 25 if (S[j] == 0) { 26 SG[i] = j; 27 break; 28 } 29 } 30 } 31 }
1 /* 2 按照卡中心校園招聘的要求,HR小招和小商需要從三個科室中(分別為A、B、C)抽派面試官去往不同城市。 3 兩名HR按照以下規定輪流從任一科室選擇面試官:每次至少選擇一位,至多選擇該科室剩余面試官數。最先選不到面試官的HR需要自己出差。 4 假設HR小招和小商都不想出差且每次選擇都采取最優策略,如果是小招先選,寫一個函數來判斷她是否需要出差。如果不需要出差,請給出第一步的最優策略。 5 */ 6 // 測試用例 2,0,4 -> c,2 1,8,9 -> 1(需要出差) 7 public class Main{ 8 public static void main(String[] args) { 9 Scanner in = new Scanner(System.in); 10 String string = in.next().toString(); 11 String stringArray[] = string.split(","); 12 int num[] = new int[stringArray.length]; 13 for (int i = 0; i < stringArray.length; i++) { 14 num[i] = Integer.parseInt(stringArray[i]); 15 } 16 int a = num[0]; 17 int b = num[1]; 18 int c = num[2]; 19 int bool = a ^ b ^ c; 20 if (bool == 0) 21 System.out.print(1); 22 else { 23 if ((a ^ b) < c) { 24 System.out.print("C," + (c - (a ^ b))); 25 } 26 if ((a ^ c) < b) { 27 System.out.print("B," + (b - (a ^ c))); 28 } 29 if ((b ^ c) < a) { 30 System.out.print("A," + (a -(b ^ c))); 31 } 32 } 33 } 34 }