这里做一个抽象,假设一推里面有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代码:

 public boolean canWinNim(int n) {

     return (n % 4) == 0 ? false : true;
}

(扩展):尼姆博弈

题型

尼姆博弈模型,大致上是这样的:

有3堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取1个,多者不限,最后取光者得胜。

获胜情况对先取者的讨论

异或结果为0,先取者必败,无获胜方法。后取者获胜;

结果不为0,先取者有获胜的取法。

拓展

任给N堆石子,两人轮流从任一堆中任取(每次只能取自一堆),取最后一颗石子的人获胜,问先取的人如何获胜?

根据上面所述,N个数异或即可。如果开始的时候T=0,那么先取者必败,如果开始的时候T>0,那么只要每次取出石子使得T=0,即先取者有获胜的方法。

最后一个奇异局势是(0,0...,0)。另一个奇异局势是(n,n,0...0),只要对手总是和我拿走一样多的物品,最后会面对(0,0...,0)。

SG函数模板:

 import java.util.Arrays;

 class Main {
// N 表示可以取的个数
// MAXN表示每堆石头的最大数
public static final int N = 20;
public static final int MAXN = 1000;
public static int[] f = new int[N];
public static int[] SG = new int[MAXN + 10];
public static int[] S = new int[MAXN + 10]; public static void main(String[] args) { } void getSg(int n) {
int i, j;
Arrays.fill(SG, 0);
for (i = 1; i <= n; i++) {
Arrays.fill(S, 0);
for (j = 0; f[j] <= i && j < N; j++)
S[SG[i - f[j]]] = 1;
for (j = 0;; j++)
if (S[j] == 0) {
SG[i] = j;
break;
}
}
}
}
 /*
按照卡中心校园招聘的要求,HR小招和小商需要从三个科室中(分别为A、B、C)抽派面试官去往不同城市。
两名HR按照以下规定轮流从任一科室选择面试官:每次至少选择一位,至多选择该科室剩余面试官数。最先选不到面试官的HR需要自己出差。
假设HR小招和小商都不想出差且每次选择都采取最优策略,如果是小招先选,写一个函数来判断她是否需要出差。如果不需要出差,请给出第一步的最优策略。
*/
// 测试用例 2,0,4 -> c,2 1,8,9 -> 1(需要出差)
public class Main{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String string = in.next().toString();
String stringArray[] = string.split(",");
int num[] = new int[stringArray.length];
for (int i = 0; i < stringArray.length; i++) {
num[i] = Integer.parseInt(stringArray[i]);
}
int a = num[0];
int b = num[1];
int c = num[2];
int bool = a ^ b ^ c;
if (bool == 0)
System.out.print(1);
else {
if ((a ^ b) < c) {
System.out.print("C," + (c - (a ^ b)));
}
if ((a ^ c) < b) {
System.out.print("B," + (b - (a ^ c)));
}
if ((b ^ c) < a) {
System.out.print("A," + (a -(b ^ c)));
}
}
}
}
05-11 22:16