Nim游戏算法问题(Java)
Nim游戏
一共有n堆石子,编号为1~n,第i堆石子有a[i]个石子,
每次操作,A和B俩人可以从任意一堆石子中取走任意数量的石子,至少取一颗,最多取出该堆所有石子
俩人轮流行动,取光所有石子的获取,A先手,
现给定数组a,俩人都采用最佳策略,问谁赢。
解法,将每个a[i]进行异或,结果若为0,那么取的过程中随便动一下结果都会变为非0
所以,A先手,如果行动前,结果为非0,就可以行为后变为0,赢了;如果行动前,结果为0,就可以行为后变为非0,输了
public class Test1 {
public static void main(String[] args) {
f2(new int[]{3,6,5});
}
static void f2(int[] arr){
int result=0;
for (int j : arr) {
result ^= j;
}
if(result!=0) System.out.println("赢了");
else System.out.println("输了");
}
}
Nim变体:Staircase Nim阶梯Nim博弈
从左到右有一排棋子,给定棋子的位置,规定每个棋子只能向左移动,且不能跨过前面的棋子,最左边的棋子最多移动到下标为1位置,
每次只选择一个棋子向左移,问先手是否能赢,当不能移动棋子时为输
例子 1 3 5 6 7 9 13 17 21 每元素表示该位置有棋子,其余位置为空(下标从1开始)
解法:先按位置进行升序排序,从后往前把棋子俩俩绑定,下标为17和21的绑定,下标为13和下标为9的绑定。如果棋子的个数为奇数个,就把最前面的棋子与下标为0的绑定
同一对棋子中,对手对前一个棋子移动若干步数,你总能对后一个棋子移动相同的步数,所以俩对棋子之间的间距没有影响
我们只需要关心同一对棋子之间的间距,转换为 有n对棋子->n个石子堆;每对棋子之间的空位->每堆石子的个数
public class Test1 {
public static void main(String[] args) {
int[] arr = new int[]{1,3,5,7,8,11,14,19};
f3(arr.length,arr);
}
static void f3(int n,int[] arr){ //arr为n个棋子的位置
Arrays.sort(arr); //按位置排序,测试给的数组可能是乱序的
int ans = 0;
if((n&1) == 1){ //棋子个数为奇数个
for(int i=0;i<n;i+=2){
ans^= (i==0) ? arr[0]-1 : arr[i]-arr[i-1]-1;
}
}else { //棋子个数为偶数个
for(int i =1;i<n;i+=2){
ans^= arr[i]-arr[i-1]-1;
}
}
if(ans==0){
System.out.println("先手输");
}else{
System.out.println("先手赢");
}
}
}