各种常见的博弈论 + 简单例题

斐波那契博弈
有一堆个数为n(n>=2)的石子,游戏双方轮流取石子,规则如下:
1)先手不能在第一次把所有的石子取完,至少取1颗;
2)之后每次可以取的石子数至少为1,至多为对手刚取的石子数的2倍。
约定取走最后一个石子的人为赢家,求必败态。
结论:当n为Fibonacci数的时为必败态。
即将斐波那契数列打表再判断n是否为斐波那契数判断即可

例题:HDU - 2516 取石子游戏
(我这里打表了,TIME是0 哦豁)

#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;

long long feibonaq[100]={
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765,
10946,
17711,
28657,
46368,
75025,
121393,
196418,
317811,
514229,
832040,
1346269,
2178309,
3524578,
5702887,
9227465,
14930352,
24157817,
39088169,
63245986,
102334155,
165580141,
267914296,
433494437,
701408733,
1134903170,
1836311903,
2971215073,
4807526976,
7778742049,
12586269025,
20365011074,
32951280099,
53316291173,
86267571272,
139583862445,
225851433717,
365435296162,
591286729879,
956722026041,
1548008755920,
2504730781961,
4052739537881,
6557470319842,
10610209857723,
17167680177565,
27777890035288,
44945570212853,
72723460248141,
117669030460994,
190392490709135,
308061521170129,
498454011879264,
806515533049393,
1304969544928657,
2111485077978050,
3416454622906707,
5527939700884757,
8944394323791464,
14472334024676221,
23416728348467685,
37889062373143906,
61305790721611591,
99194853094755497,
160500643816367088,
259695496911122585,
420196140727489673,
679891637638612258,
1100087778366101931,
1779979416004714189,
2880067194370816120,
4660046610375530309,
7540113804746346429};

int main() {
    ios::sync_with_stdio(false);
    ll n;
    while(~scanf("%lld",&n)) {
        if(n==0) break;
        int flag=0;
        if(n<=2971215073) {
            for(int i=1;i<=45;i++) {
                if(n<feibonaq[i]) break;
                if(n==feibonaq[i]) {
                    flag++;
                    break;
                }
            }
        }
        else {
            for(int i=46;i<=90;i++) {
                if(n<feibonaq[i]) break;
                if(n==feibonaq[i]) {
                    flag++;
                    break;
                }
            }
        }
        if(flag==1) printf("%s\n","Second win");
        else printf("%s\n","First win");
    }
    return 0;
}

巴什博弈
只有一堆n个物品,两个人轮流从中取物,规定每次最少取一个,最多取m个,最后取光者为胜。
结论:一轮最多拿的就是1+m个,所以控制下去,最后的不到(1+m)的物品肯定会被后手拿到的。
即判断n能不能除尽m+1,如若能则后手必胜

例题:HDU - 1846 Brave Game

#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        //如果m+1>=n,则后手必胜,说明当是这种情况的倍数时,后手能够一直制作出这种情况,则后手必胜
        if(n%(m+1)==0) cout<<"second"<<endl;
        else cout<<"first"<<endl;
    }
    return 0;
}

尼姆博弈
有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。
结论:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。

例题:POJ - 2234 Matches Game

#include <iostream>
//#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;

int k[100];

int main() {
    ios::sync_with_stdio(false);
    int n;
    while(cin>>n) {
        int tmp=0;
        for(int i=0;i<n;i++) {
            cin>>k[i];
            tmp^=k[i];
        }
        if(tmp==0) cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    }
}

乘法博弈
2 个人玩游戏,从 1 开始,轮流对数进行累乘,直到超过一个指定的值m时,该玩家获胜。
如果乘数范围是2~n,
则如果m为2~n,则先手必胜。
如果是n+1~2×(上一个后范围),则后手必胜,因为无论第一次先手乘的数是什么,数必在2到n之间
结论:必胜态对称,于是将m不断除与2n,判断余数在2到n还是n+1到2n之间即可

例题:POJ - 2505 A multiplication game

#include <iostream>
//#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    long double n;
    while(cin>>n) {
        while(n>18) {
            n/=2;
            n/=9;
        }
        if(n<=9) cout<<"Stan wins."<<endl;
        else cout<<"Ollie wins."<<endl;
    }
}

环形博弈
n个石子围成一个环,每次取一个或者取相邻的2个。
证明:以后再写(
结论:石子数目小于等于2 先手胜,其他 后手胜。

例题:POJ - 2484 A Funny Game

#include <iostream>
//#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    int n;
    while(cin>>n&&n!=0) {
        if(n<=2) cout<<"Alice"<<endl;
        else cout<<"Bob"<<endl;
    }
}

对称博弈
n个石子围成环,每次只能取相邻的1 - k个
结论:如果k<n:对k=1,如果n能被2整除,则后手赢
如果k>1,后手赢(先手取什么位置后手就取对称的位置,这样保证后手永远能取到)
如果k>=n:先手赢

例题:HDU - 3951 Coin Game

#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    for(int i=1;i<=t;i++) {
        int n,k;
        cin>>n>>k;
        cout<<"Case "<<i<<": ";
        if(k<n) {
            if(k==1) {
                if(n%2==0) cout<<"second"<<endl;
                else cout<<"first"<<endl;
            }
            else cout<<"second"<<endl;
        }
        else cout<<"first"<<endl;
    }
}

威佐夫博弈
有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。
结论:看两个数的差值t是不是满足 (sqrt(5)+1)/2*t==min(n1,n2);,是的话则后手必胜

例题:HDU - 1527 取石子游戏

#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    int a,b;
    double temp;
    while(cin>>a>>b) {
        if(a>b) swap(a,b);
        temp=floor((b-a)*(1+sqrt(5.0))/2.0);
        if(temp==a) cout<<0<<endl;
        else cout<<1<<endl;
    }
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值