0
点赞
收藏
分享

微信扫一扫

【基础数论】取石子游戏&博弈问题

SDKB英文 2022-03-11 阅读 77

问题描述

蒜头君和花椰妹在玩一个游戏,他们在地上将 n 颗石子排成一排,编号为 1 到 n。开始时,蒜头君随机取出了 2 颗石子扔掉,假设蒜头君取出的 2 颗石子的编号为 a, b。游戏规则如下,蒜头君和花椰妹 2 人轮流取石子,每次取石子,假设某人取出的石子编号为 i,那么必须要找到一对 j, k 满足 i=j−k 或者 i=j+k ,并且编号为 j,k 的石子已经被取出了,如果谁先不能取石子了,则视为输了。蒜头君比较绅士,让花椰妹先手。
输入格式
第一行输入一个整数 t(1≤t≤500),表示蒜头君和花椰妹进行了 t 局游戏。
对于每局游戏,输入 3 个整数 n(2≤n≤20000),a,b(1≤a,b≤n),保证 a,b 不相等。
输出格式
如果蒜头君赢了游戏,输出一行suantou,如果花椰妹赢了,输入一行huaye。

样例输入

5
8 6 8
9 6 8
10 6 8
11 6 8
12 6 8

样例输出

suantou
suantou
huaye
huaye
suantou
思路:题意是有一堆石子,游戏之前先取出两个,然后女生开始两个人轮流取石子,取出的石子必须是最开始取出两石子的和或差,即pa+qb,而pa+qb=k*gcd(a,b),所以题目转化为找取出两石子编号的最大公约数,看1~n中有多少个两石子的最大公约数,如果为奇数个最大公约数女生赢,反之男生赢

#include <iostream>
using namespace std;
int t,a,b,n,d;
int gcd(int a,int b){
    if(b==0) return a;
    else return gcd(b,a%b);
}
int main(){
    cin>>t;
    for(int i=0;i<t;i++){
        cin>>n>>a>>b;
        d=n/gcd(a,b)%2;
        if(d==0) cout<<"suantou"<<endl;
        else cout<<"huaye"<<endl;
    }
    return 0;
}

巴什博弈

巴什博奕:只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。

显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。
因此我们发现了如何取胜的法则: 如果n=(m+1)* r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)*(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。

简单来说就是最后一手给自己留下<=m个。

斐波那契博弈(Fibonacci Nim)

有一堆个数为n(n>=2)的石子,游戏双方轮流取石子,规则如下:

1)先手不能在第一次把所有的石子取完,至少取1颗;

2)之后每次可以取的石子数至少为1,至多为对手刚取的石子数的2倍。

约定取走最后一个石子的人为赢家,求必败态

举报

相关推荐

0 条评论