《编程之美-微软技术面试心得》这本书中的1.11节有一个问题:
一堆石块,A和B两个人从里面拿,每次只能拿一个或者任意连续的两个,最后拿到的算赢,先拿者是否有必胜策略:
这个问题较为简单:先拿者有必赢策略,只要按照如下规则拿即可,如果有奇数个石块,先拿者只拿中间的一个,如果偶数块,先拿者拿中间的两个,之后的策略就很简单了,和对手对称的拿就行了,对手怎么拿,先拿者也怎么拿,一定会拿到最后一块。
现在将问题转化一下,如果最后拿到算输的话,先拿者是否还有必胜策略呢??
如果共有1个石块,有必赢策略
2:有
3:有
4:无
5:有(拿掉边上的一个,就使得对方没有必赢策略)
6:有(拿掉边上的两个)
规则1:如果n没有必赢策略,那么n+1和n+2一定有必赢策略
给定一堆石块n个,怎样判断先拿者是否有必胜策略呢,就是判断从n个石块任意拿一个或者连续的两个,以后的结果如果没有必赢策略,那么这n个石块的堆就有了必赢策略:
用[x,y]表示一个被拆分了的堆,首先计算[x,y]是否有必赢策略。
规则2:n个石块的一段,拿掉任意一个或者连续的两个以后剩下[x,y],如果任意一种情况没有必赢策略,那么n个一堆就有必赢策略,否则,没有必赢策略
规则3:[x,y]是否有必赢策略可以通过和规则2一样的推理方法,又所有[x,y]的拆分情况是否有必赢策略决定。
规则4:初始条件相关,奇数个1的组,有必赢策略,退化为1个1的组,偶数个1,无必赢策略,退化为两个1的组。
使用以上4个规则,则可以得出一个算法:
package shikuai;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
/**
*
* 一堆石块,A和B两个人从里面拿,每次只能拿一个或者任意连续的两个,最后拿到的算输,先拿者是否有必胜策略
*
* @author wan
*
*/
public class ShiKuaiProblem {
static class ShiKuai implements Comparable<ShiKuai>