ACM博弈论总结

常用的4个博弈论算法
巴什博奕,威佐夫博奕,尼姆博奕,斐波那契博弈

1.巴什博奕

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

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

#include<iostream>  
#include<string>  
#include<cstring>  
#include<cstdio>  
#include<algorithm>  
using namespace std;  

int main()  
{  
    int N, num, limit;  
    scanf("%d", &N);  
    while(N--)  
    {  
        scanf("%d%d", &num, &limit);  
        if(num % (limit + 1) != 0) //必胜局面  
            printf("Win\n");  
        else  
            printf("Lose\n");  
    }  
    return 0;  
}          

2.威佐夫博奕

讲解 后来补上 。。。。
这种博弈比前面一种要稍微复杂一点。我们来看下下面这个游戏。
有两堆火柴棍,每次可以从某一堆取至少1根火柴棍(无上限),或者从两堆取相同的火柴棍数。最后取完的是胜利者。

只要记住公式:a[i] = i*(1+√5)/2 b[i] = a[i]+i;

我们用a[i]表示失败态中的第一个,b[i]表示失败态中的第二个.(i从0开始).

#include<iostream>  
#include<string>  
#include<cstring>  
#include<cstdio>  
#include<cmath>  
#include<algorithm>  
using namespace std;  

int main()  
{  
    int num1, num2, tmp; //第一堆剩的数量为num1,第二堆剩num2  
    while(scanf("%d%d", &num1, &num2) != EOF)  
    {  
        if(num1 > num2)  
            swap(num1, num2);   
        tmp = floor((num2 - num1) * (1 + sqrt(5.0)) / 2.0); //黄金分割  
        if(tmp == num1) printf("Lose\n"); //奇异局势必败  
        else    printf("Win\n");  
    }  
    return 0;  
}          

3.尼姆博奕

指的是这样的一个博弈游戏,目前有任意堆石子,每堆石子个数也是任意的,双方轮流从中取出石子,规则如下:
1)每一步应取走至少一枚石子;每一步只能从某一堆中取走部分或全部石子;
2)如果谁取到最后一枚石子就胜。

判断当前局势是否为必胜(必败)局势:
把所有堆的石子数目用二进制数表示出来,当全部这些数按位异或结果为0时当前局面为必败局面,否则为必胜局面;

#include<iostream>  
using namespace std;  
int temp[ 20 ]; //火柴的堆数  

int main()  
{  
    int i, n, min;  
    while( cin >> n )  
    {  
        for( i = 0; i < n; i++ )  
            cin >> temp[ i ]; //第i个火柴堆的数量  
        min = temp[ 0 ];  
        for( i = 1; i < n ; i++ )  
            min = min^temp[ i ]; //按位异或  
        if( min == 0 )  
            cout << "Lose" << endl; //输  
        else  
            cout << "Win" << endl; //赢  
    }  
    return 0;  
}  

4.斐波那契博弈

有一堆个数为n的石子,游戏双方轮流取石子,满足:

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

2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。

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

这个游戏叫做斐波那契博弈,肯定和斐波那契数列:f[n]:1,2,3,5,8,13,21,34,55,89,… 有密切的关系。如果试验一番之后,可以猜测:先手胜当且仅当n不是斐波那契数。换句话说,必败态构成斐波那契数列。

fib[0]=1;  
    fib[1]=2;  
    for(i=2;i<45;i++)   //假设有最多有45个人
        fib[i]=fib[i-1]+fib[i-2];  
    while(scanf("%d",&n)&&n)  
    {  
        for(i=0;i<45;i++)   
        {  
            if(fib[i]==n)  
                break;  
        }  
        if(i<45)  
            printf("Second win\n");  
        else  
            printf("First win\n");  
    }  
    return 0;  
}  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值