我们约定:
每个人从盒子中取出的球的数目必须是:1,3,7或者8个。
轮到某一方取球时不能弃权!
A先取球,然后双方交替取球,直到取完。
被迫拿到最后一个球的一方为负方(输方)
请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A是否能赢?
分析:
f(局面 x) ---> 胜负
边界条件处理
for(对我所有可能的走法)
{ 试着走一步 -----> 局面y
胜负 t = f(y);
if(t==负) return 胜 局面
return 负
也就是说,让A去尝试它走哪一步不会输,他走出一步后,局面发生改变,由对手去下剩下的局面,通过判断对手的输赢来判断自己的输赢。
解法一:
public class Main {
public static boolean f(int n)
{
if(n==0) return true; //边界处理,不论对于哪方来说,如果拿的时候没有球可拿,则说明最后一个球被对方拿走,自己就赢了
if(n>=1&&f(n-1)==false) return true; //对A来说,如果球数大于一个,就先尝试着去一个,如果取一个,对方输了,就返回true,代表我方赢
if(n>=3&&f(n-3)==false) return true; //否则尝试着取3个球,以此类推,如果所有尝试都不可以取胜,则返回false。
if(n>=7&&f(n-7)==false) return true;
if(n>=8&&f(n-8)==false) return true;
return false;
}
public static void main(String[] args) {
System.out.println(f(10));
System.out.println(f(1));
System.out.println(f(4));
}
}
解法二:根据题目的意思,我们可以推出一些局面的情况。
由于题目的要求,两个人取球,其中每人每一次必取 1, 3, 7, 8 其中的一个数量的球,并且最后一个球被取到的人输,因此我得出以下表格:
先我拿 | 先他拿 | 记录表表示了初始的总球数,所对应的游戏情况 | |||||||||
我败 | 我胜 | 1 | 3 | 5 | 7 | 16 | 18 | 20 | 22 | 31 | ..... |
我胜 | 我败 | 2 | 4 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | ..... |
表格中的 失败 胜利,均是相对于“我”而言的。
因此对于A君先取球,判断A君的游戏情况,可以把“我先拿胜利”的情况均存在r[]数组中并赋值为1,否则r[]数组中其他值赋值为0,即可。
表格的具体构造过程如下:
初始值:int r[10003]={1,0,1,0,1,0,1,0,1}; //*-1表示0个球的情况不存在,存了8个球进去了下标从0开始的 *//
然后 i = 9;判断 ( r[i-8]==1&& r[i-3]==1&& r[i-7]==1 && r[i-1]==1 ),
如果成立,说明无论我走哪一步,对方都可以胜利, 则r[i] = 1 否则r[i] = 0;
代码:
public class Main {
public static void main(String[] args) {
int[] book = new int[1000];
book[0] = -1; book[1] = 0; book[2] = 1;
book[3] = 0; book[4] =1; book[5] = 0;
book[6] = 1; book[7]=0; book[8] = 1;
for(int i=9;i<book.length;i++)
{
if((book[i-1]==0)&&(book[i-3]==0)&&(book[i-7]==0)&&(book[i-8])==0)
{
book[i] = 0;
}else {
book[i] =1;
}
}
System.out.println(book[10]);
}
}
总结:代码一采用递归的形式写,效率不是很高,方式二时间复杂度为N,值的推荐。
这是没有平局的博弈问题,有平局的可参考后面的博文。