二人轮流取硬币。
每人每次只能从某一堆上取任意数量。
不能弃权。
取到最后一枚硬币的为赢家。
求先取硬币一方有无必胜的招法。
分析:
这种问题有数学家已经提出了解决方案。
只要是是这种可以取任意数量的问题都可以用尼姆的方法解决
做法
首先将 3 堆硬币 全部转换成 2 进制 再对他们进行异或处理
011
100
101
===异或后
010
改变数据,就代表:
使这部分数据改变一下 就可以使先拿的一方必胜
改变这3堆数据的某几位,让结果等于0
001
100
101
改变第一堆数据
011
110
101
改变第二堆数据(错误的做法,因为硬币是不会变多的。)
011
100
111
改变第三堆数据。(错误的做法,因为硬币是不会变多的。)
异或的运算法则还没有摸清楚,停几天来补文章,现在介绍使用方法
import java.util.Arrays;
public class Main {
public static void f(int[] arr){
int num = 0;
//计算出最后的异或值
for(int i=0;i<arr.length;i++){
num ^= arr[i];
}
for(int i=0;i<arr.length;i++){
//让最后的结果尝试去和其中的一个值异或。
//相当于就变成了 其余得到了 其余几个值的 异或结果
int temp = num ^ arr[i];
//符合拿球逻辑
if(temp<=arr[i]){
//这样拿球能赢
System.out.println(arr[i]+"-->"+(arr[i]-temp));
}
}
}
public static void main(String[] args) {
int[] a = {2,5,12,14};
int[] b = {3,4,5};
System.out.println(Arrays.toString(a));
f(a);
System.out.println(Arrays.toString(b));
f(b);
}
}
尼姆堆进阶问题
高僧斗法
古时丧葬活动中经常请高僧做法事。
仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。
又有若干小和尚随机地“站”在某个台阶上。
最高一级台阶必须站人,其它任意。(如图所示)
两位参加斗法的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。
两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。
轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。
输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N<100, 台阶总数<1000)
输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。
若有多个解,输出A值较小的解,若无解则输出-1。
例如:
用户输入:
1 5 9
则程序输出:
1 4
再如:
用户输入:
1 5 8 10
则程序输出:
1 3
解法不是太理解,会使用模板套过程,停几天来更新自己的理解这几天比较忙
import java.util.Arrays;
public class Main {
static void f(int[] a){
for(int i=0;i<a.length-1;i++){
for(int j=a[i]+1;j<a[i+1];j++){
int temp = a[i];
try{
a[i] = j;
if(v(a)){
System.out.println(temp+" "+j);
return;
}
}finally{
a[i]=temp;
}
}
}
System.out.println(-1);
}
public static boolean v(int[] a){
int num =0;
for(int i=0;i<a.length-1;i+=2){
num ^= a[i+1]-a[i]-1;
}
return num==0;
}
public static void main(String[] args){
int[] a = {1,5,9};
int[] b = {1,5,8,10};
f(a);
f(b);
}
}