博弈论——组合游戏(Bash和nim)

文章探讨了几种基于博弈论的游戏策略,包括bash游戏、删除质因数游戏、数字删除游戏、日历游戏以及nim游戏变体。通过确定终态、倒推状态和利用PN态性质,解决这些游戏中先手是否获胜的问题。nim游戏的核心在于异或运算,通过计算所有堆石子的异或和判断先手优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博弈论1

组合游戏

特征

  • 两个玩家
  • 一个状态集合
  • 游戏规则是指明玩家从一个状态可以移动到哪些状态
  • 玩家轮流进行移动
  • 如果当前处于的状态无法移动,则说明游戏结束
  • (大部分时候)无论玩家如何选择,游戏会在有限步操作内结束

通常的解题步骤

  • 首先设置两种状态P,N 态
    • P:走到这个状态的玩家(previous player)赢的状态
    • N:从这个状态走的玩家(next player)赢的状态
  • 确定终态是 P 还是 N
  • 从终态逆推打表找规律
  • 验证规律的正确性
  • 确定初态是 p 还是 N
    • 初态是 P 意味着先手输
    • 否则意味着先手赢

P N 态的性质

  • 至少能走到一个P态的状态是N态
  • 下一步只能走到N态的状态是P态

题目分析

bash游戏

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

枚举m,进行倒推打表
比如:

m = 1
0(P) <—— 1(N) <—— 2(P) <—— 3(N) .....
m = 2
0(P) <—— 1(N) <—— 2(N) <—— 3(P) .....
m = 3
0(P) <—— 1(N) <—— 2(N) <—— 3(N) <—— 4(P).....

然后我们可以初步的确定结论为
if(num % (m + 1) == 0) num 为 P 态
else num 为 N 态

最后可以去确定n的状态,判断先手是赢还是输

题目和代码
#include<iostream>
#include<algorithm>
using namespace std;

int t;

void solve()
{
   
   
    int n,k;
    cin >> n >> k;
    if(n % (k + 1)) puts("A");
    else puts("B");
}

int main()
{
   
   
    cin >> t;
    while(t --) solve();
    return 0;
}
eleting Divisors
  • 首先我们可以确定终态为质数,我们可以直接确定质数为P态
  • 从1开始从小到大确定每个数的状态
  • 根据PN性质,能到达P态的是N态,只能到达N态的是P态,然后打表找规律
  • 发现奇数全为P态
  • 偶数分为两种情况
    • 如果是2的整奇数次幂,那么为P态
    • 否则为N态
打表代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<fstream>
#include<vector>
#include<unordered_map>
using namespace std;

unordered_map<int,bool> mp;
vector<int> device;

void get(int x)
{
   
   
    for(int i = 2; i * i <= x; i ++)
        if(x % i == 0) 
        {
   
   
            device.push_back(i);
            device.push_back(x / i);
        }
}

int main()
{
   
   
    for(int i = 0; i <= 200; i++) 
    {
   
   
        device.clear();
        get(i);
        if(device.empty()) mp[i] = 1;
        else 
        {
   
   
            bool flag = true;
            for(int d : device)
                if(mp[i - d])
                {
   
   
                    flag = false;
                    break;
                }
            mp[i] = flag;
        }
    }
    fstream fstrm("output.txt");
    for(int i = 1; i <= 200; i++) fstrm << i << ' ' << (mp[i]? 'P':'N')  << endl;
    fstrm.close();
    return 0;
}

提交代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int t;

void solve()
{
   
   
    int n;
    cin >> n;
    if(n % 2) puts("Bob");
    else 
    {
   
   
        int cnt = 0,pos = -1;
        for(int i = 0; i < 32; i++)
            if(n >> i & 1)
            {
   
   
                cnt ++;
                if(cnt == 1) pos = i;
            }
        //cout << cnt << ' ' << pos << endl;
        if(cnt == 1 && pos & 1) puts("Bob");
        else puts("Alice");
    }
}

int main()
{
   
   
    cin >> t;
    while(t--) solve();
    return 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值