博弈论入门

博弈论入门

一.巴士博弈(Bash Game)

eg1.
拿石头,一共有n个石头Alice和Bob每人每回合可以拿1~m - 1个石头最后一个拿石头的人获胜。
n =
1 / 2 / 3 先手胜
4 后手胜
5 / 6 / 7 先手胜
8 后手胜
9 / 10 / 11 先手
n % m == 0 后手胜 n % m != 0 先手胜

例题:HDU1846

#include <bits/stdc++.h>

using namespace std;

int c, n, m;

int main()
{
    cin >> c;

    while(c--)
    {
        cin >> n >> m ;
        if(n % (m + 1) == 0)    cout << "second\n";
        else                    cout << "first\n";
    }
    return 0;
}

eg2.
Alice和Bob在下棋,一开始在(1,1)点每人每次可以向下,向右,向右下走一步,谁先走到(n,m)点谁就赢了。
必败态:
n = 1, m = 1; n = 3, m = 3;
如果n和m都是奇数,后手胜,否则先手胜

例题:HDU2147

#include <bits/stdc++.h>

using namespace std;

int n, m;

int main()
{
    while(cin >> n >> m && m + n)
    {
        if(n % 2 == 1 && m % 2 == 1)    cout << "What a pity!\n";
        else    cout << "Wonderful!\n";
    }
    return 0;
}

二.Fibonacci’ s Game(斐波那契博弈)

eg1.

有一堆个数为n的石子,游戏双方轮流取石子,满足:
1)先手不能在第一次把所有的子取完;
2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。
必败态:n是斐波那契数列

​ 必胜态:n不是

Zeckendort定理(齐肯多夫定理):任何正整数可以表示为若千个不连续的Fibonacci数之和。

例题:HDU2516

#include <bits/stdc++.h>

using namespace std;

int n;
set<int>    st;
int fib[50];

int main()
{
    fib[1] = 1;
    fib[2] = 1;
    st.insert(1);
    for(int i = 3; i <= 46; ++i)
    {
        fib[i] = fib[i - 1] + fib[i - 2];
        st.insert(fib[i]);
    }

    while(cin >> n && n)
    {
        if(st.count(n))     cout << "Second win\n";
        else    cout << "First win\n";
    }
    return 0;
}

三.威佐夫博弈(Wythoff Game)

有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多
者不限,最后取光者得获胜。

结论:首先黄金比例:r=1.618 = (sqrt(5.0) + 1) / 2,则给定两组石头堆(n,m),假设n>m,则当(n-m)*r==m时,先手输。否则后手输

*补充:floor函数

1、函数原型:

1 double floor (double x );
2 float floor (float x );
3 long double floor ( long double x );

2、功能:返回一个小于传入参数的最大整数

3、参数:x为将来被处理的数

4、返回值:返回不大于x的最大整数

(所以说这玩意跟(int)强制类型转换基本一样)

例题:HDU1527

#include <bits/stdc++.h>

using namespace std;

int a, b, t;
double r, c;

int main()
{
    r = (sqrt(5.0) + 1) / 2;

    while(cin >> a >> b)
    {
        if(a < b)   swap(a, b);
        c = double(a - b);
        t = (int)(r * c);
        if(t == b)  cout << 0 << '\n';
        else    cout << 1 << '\n';
    }
    return 0;
}

四.尼姆博弈(Nimm Game)

有n堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

​ 必败态(奇异局势):所有堆石子数异或和为0

​ 如何将一个非奇异局势(异或和不为0)转化为奇异局势?

以三堆石子为例(a,b,c)(a<b<c)只需将第三堆石子数变为a^b个即可,即从c中减去c - a^b个石子。

例题:HDU1850

#include <bits/stdc++.h>

using namespace std;

int m;
int ar[105];
int ans, sum, k;

int main()
{
    while(cin >> m && m)
    {
        ans = sum = 0;
        memset(ar, 0, sizeof(ar));
        for(int i = 1; i <= m; ++i)
        {
            cin >> ar[i];
            ans ^= ar[i];
        }
        if(ans == 0)    cout << 0 << '\n';
        else
        {
            for(int i = 1; i <= m; ++i)
            {
                k = ans ^ ar[i];
                if(ar[i] >= k)  sum++;
            }
            cout << sum << '\n';
        }
        
    }

    return 0;
}

还有一个叫sg函数的东东~~
(待更新)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值