GCD博弈

有两堆石子,两个人轮流去取.每次取的时候,只能从较多的那堆石子里取,并且取的数目必须是较少的那堆石子数目的整数倍.最后谁能够把一堆石子取空谁就算赢. 
比如初始的时候两堆石子的数目是25和7

25 7 –> 11 7 –> 4 7 –> 4 3 –> 1 3 –> 1 0

选手1取 
选手2取 
选手1取 
选手2取 
选手1取

最后选手1(先取的)获胜,在取的过程中选手2都只有唯一的一种取法。 
给定初始时石子的数目,如果两个人都采取最优策略,请问先手能否获胜。

这又是一道博弈论的题,似乎是一道很基础的题,但是我依然不会做。 
是这个样子的,设aba≤b,则若a2ba≤2b或b|a,则先手必胜,否则先手只有一种取法,就取下这种,看后手是否会赢,如此递归下去,时间复杂度是log级的。 
考虑为什么这种情况下先手必胜。 
对于b|a的情况是显然的,而若a2ba≤2b,我们考虑a%b,假如a%bb2a%b≤⌊b2⌋,则显然我们取bab1b∗⌊ab−1⌋即可令后手选法唯一且在其选过之后,留给先手的是aba≤b或b|a的局面;而同样的道理,若a%b>b2a%b>⌊b2⌋,我们只需取babb∗⌊ab⌋即可。 
所以我们便找到了必胜态。 
代码很短:

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int main(){
    int n,m,tot;
    for(scanf("%d%d",&n,&m);n||m;scanf("%d%d",&n,&m)){
        if(n<m)swap(n,m);
        if(n/m>=2||n%m==0)puts("win");
        else{
            tot=0;
            do{
                n-=m;
                swap(n,m);
                ++tot;
            }while(n/m<2&&n%m);
            if(tot&1)puts("lose");
            else puts("win");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

= =但是我感觉,博弈论的题证明起来好说,正面推的话就蛋疼;做题的时候。。还是先打表找规律,再深入思考吧。。不过大体思路似乎都是寻找必败态或必胜态,然后再从一个搞出另一个。

猜你喜欢

转载自blog.csdn.net/gipsy_danger/article/details/80612230
gcd
今日推荐