石头游戏

【座右铭】1. 想要成为行家,就必须尝试解决大量的问题;

                    2. 解决大量问题并不代表能解决所有问题,而是表示解决下一个问题的几率变大了


1.有65颗宝石,两个人来取,规则是每次必须且只能取1-3颗,取完后,手中为偶数颗的取胜,请编制一个先手必胜的取法程序【问题来源于论坛】

第一部分:思路

1.定义一个N*4的矩阵的矩阵:

 

1个石头

2个石头

3个石头

4个石头

[奇,奇]

(1,1)

(0,1)

(1,3)

(0,1)

 

[奇,偶]

(0,1)

(1,1)

(0,1)

(1,3)

 

[偶,奇]

(0,1)

(1,2)

(0,2)

(-1,1)

 

[偶,偶]

(-1,1)

(0,2)

(1,2)

(0,2)

 

第1列的二元组分别表示第一个人和第二个人在取石头之前手上的石头数。例如[奇,奇]表示第一个人手上为奇数个石头,第二个人手上为奇数个石头。

第2列的二元组分别表示第一个人是否获胜,以及如何取石头。例如(1,1)表示第一个人取1个石头肯定获胜;(0,1)表示最好的结局是平均,取1颗石头;(-1,1)表示第一个人肯定会输,取1颗石头

2.在初始化1、2、3个石头后,以后的胜负可依次推导出,例如:

设T(i,[奇,奇])表示二人在第i个石头(i>3)前,手上的石头数都为奇数,则有:

T(i,[奇,奇]) = max{-1*T(i-1,[奇,偶]),-1*T(i-2,[奇,奇]),-1*T(i-3,[奇,偶])},其中“-1*T(i-1,[奇,偶])”表示第一个人取了1个石头后,手上就有偶数个石头。轮到第二个人取时,就把第一个人和第二个人调换下,然后从矩阵的第i-1列获知胜负,然后将胜负再调换。

第二部分:Java代码,不考虑异常情况

public class Game {
	private Game(){}
	
	/**
	 * 对外接口,返回N*4*2的矩阵
	 * @param number
	 * 输入的石头数
	 * @return
	 * 返回N*4*2的矩阵
	 */
	public static int[][][] start(int number)
	{
		number = number>3?number:3;
		int[][][] path = new int[number+1][4][2];
		//初始化1颗石头
		path[1][0][0] = 1; path[1][0][1] = 1;
		path[1][1][0] = 0; path[1][1][1] = 1;
		path[1][2][0] = 0; path[1][2][1] = 1;
		path[1][3][0] = -1; path[1][3][1] = 1;
		//初始化2颗石头
		path[2][0][0] = 0; path[2][0][1] = 1;
		path[2][1][0] = 1; path[2][1][1] = 1;
		path[2][2][0] = 1; path[2][2][1] = 2;
		path[2][3][0] = 0; path[2][3][1] = 2;
		//初始化3颗石头
		path[3][0][0] = 1; path[3][0][1] = 3;
		path[3][1][0] = 0; path[3][1][1] = 1;
		path[3][2][0] = 0; path[3][2][1] = 2;
		path[3][3][0] = 1; path[3][3][1] = 2;
		
		for(int i=4;i<=number;i++)
		{
			for(int j=0;j<4;j++)
			{
				//拿1颗石头
				int p = exchange(j,1);
				path[i][j][0] = -1*path[i-1][p][0];
				path[i][j][1] = 1;
				//拿2颗石头
				p = exchange(j,2);
				int result = -1*path[i-2][p][0];
				if(result>path[i][j][0])
				{
					path[i][j][0] = result;
					path[i][j][1] = 2;
				}
				//拿3颗石头
				p = exchange(j,3);
				result = -1*path[i-3][p][0];
				if(result>path[i][j][0])
				{
					path[i][j][0] = result;
					path[i][j][1] = 3;
				}
			}
		}
		
		return path;
	}
	
	/*
	 * 奇偶对调 
	 */
	static int exchange(int index, int stone)
	{
		//第一人的手上石头数发生改变
		if(stone==1||stone==3)
		{
			switch(index)
			{
				case 0:index=2;break;
				case 1:index=3;break;
				case 2:index=0;break;
				default: index=1;
			}
		}
		
		switch(index)
		{
			case 0:return 0;
			case 1:return 2;
			case 2:return 1;
			default: return 3;
		}
	}
	
}

第三部分:测试用例

在输入石头数为65时,结果如下所示:

[偶,偶]:-1 0 1 0 1 0 1 0 -1 0 1 0 1 0 1 0 -1 0 1 0 1 0 1 0 -1 0 1 0 1 0 1 0 -1 0 1 0 1 0 1 0 -1 0 1 0 1 0 1 0 -1 0 1 0 1 0 1 0 -1 0 1 0 1 0 1 0 -1 

从该序列中可知,当石头数为65时,先出手必败。而且还可从发现如下规律:

1)当石头数模8余1时,先手必败

2)当石头数模8余3,5,7时,先手必胜

3)当石头数模8余0,2,4,6时,平局

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值