leetcode1025除数博弈——SG函数

题目:
爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。

最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:

选出任一 x,满足 0 < x < N 且 N % x == 0 。
用 N - x 替换黑板上的数字 N 。
如果玩家无法执行这些操作,就会输掉游戏。

只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。

示例 1:

输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。
示例 2:

输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。

提示:

1 <= N <= 1000

题解:
好像是个博弈论的题,原以为是知识不够,看完别人的代码发现是智商不够。
引用一个博弈论的博客,讲的挺好

https://blog.csdn.net/strangedbly/article/details/51137432

引用两种实现:
1:

~~~c
class Solution {
public:
    int h[1005];
    bool temp[1005];
    void SG(int x)
    {
	    memset(temp, 0, sizeof(temp));
	    for (int i = 1; 2 * i <= x; i++)
	    {
		    if (x%i == 0)
		    {
		    	temp[h[x-i]] = 1;
		    }
	    }
	    for (int i = 0; i <= x; i++)
	    {
		    if (temp[i] == 0)
		    {
			    h[x] = i;
			    break;
		    }
	    }
    }
    bool divisorGame(int N) 
    {
	    h[0] =0;
        h[1]=0;
	    for (int i = 2; i <= N; i++)
	    {
		    SG(i);
	    }
        if(!h[N])
            return false;
        return true;
    }
};
~~~

2:

~~~c
class Solution {
    //带备忘录机制的递归(动态规划)
    public boolean divisorGame(int N) {
        int []a = new int[N+1];
        for(int i=0;i<=N;i++){
            a[i] = -1;
        }
        int i = 0;
        return divisor(a,N,i);
    }
    
    //分析游戏胜利条件 N=1时,游戏就结束了
    //用i表示回合数,初始为0,当回合数为偶数时,表示爱丽丝的回合
    //a[N]为1表示游戏能继续下去,为0表示不能继续下去
    boolean divisor(int []a,int N,int i){
        //如果已经给a[N]赋值
        if(a[N]!=-1) {                 
            if(a[N] == 0){      //游戏不能继续下去了
                if(i%2 == 0) return false;   //是爱丽丝的回合,返回flase
                else return true; //是bob的回合
            }
            else{
                if(i%2 == 0) return true;
                else return false;
            } 
        }
        //还没有给a[N]赋值
        if(N==1&&i%2==0) {
            a[N] = 0;
            return false;
        }
        else if(N==1&&i%2==1) {
            a[N] = 0;
            return true;
        }
        
        else {
            int flag = 0;
            //只要有一个x能使得a[N-x]为真,flag就不为0
            for(int x=1 ;x<N ;x++){
                if(N%x == 0){
                    divisor(a,N-x,i+1);
                    if(a[N-x] == 1) flag = flag + 0;
                    else flag = flag + 1;
                }
            }
            
            if(flag!=0) {
                a[N] = 1;
                if(i%2 == 0) return true;
                else return false;
            }
            
            else {
                a[N] =0;
                if(i%2 == 0) return false;
                else return true;
            }
        }
    }
}
~~~

然后是最简单的实现:
奇数操作完一定是偶数,偶数操作完可即可偶。利用这一点,一直操作,使得剩给对面的是奇数就行了,这样你就能拿到2。而如果N是偶数,Alice可以利用规律让对方一直拿奇数,Alice win;如果N是奇数,Alice拿完就变成了偶数,这样相当于Bob拿了偶数,Bob win。

bool divisorGame(int N) {
        return N%2==0; 
    }

… :
....

猜你喜欢

转载自blog.csdn.net/weixin_41900122/article/details/89762180