尼姆堆问题(组合博弈)

有3堆硬币,分别是3,4,5
二人轮流取硬币。
每人每次只能从某一堆上取任意数量。
不能弃权。
取到最后一枚硬币的为赢家。


求先取硬币一方有无必胜的招法。


分析:

这种问题有数学家已经提出了解决方案。

只要是是这种可以取任意数量的问题都可以用尼姆的方法解决

做法

首先将 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);	
	}
    
   
}



  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SUNbrightness

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值