博弈论做题总结1

关于博弈论的基本内容详见本人这篇博客博客链接
这里以例题,补充一些博弈论的其他知识和做题的注意点。

Calendar Game(日期)

题目大意

两个人玩一种游戏,游戏内容为:在1900年1月1日到2001年11月4日之间的某一个日期开始,分别往下报日期,有两种报法,可以报该天的下一天,也可以报下个月的这一天(如果下个月没有这一天则不可以这样报),最后报到2001年11月4日的人赢。问对于给定的日期,先手是赢是输。(两人均采用最优策略)

分析

  1. 一个博弈论的相关定理:
    我们假设 所有终结点 是 必败点P。
    无论如何操作,必败点P 都只能进入 必胜点 N。(不管怎么做,都会使对手处于必胜状态)
    从任何必胜点N 操作,至少有一种方式可以进入必败点 P。(当前状态 采取 最优策略 可以使对手 处于必败状态)
    假设我站在先手的状态:
    (注意: a -> b, 如果b全部是必胜态, 则a是必败态, 如果存在一个b是必败态,则a是必胜态。)
  2. 通常我们分析必胜点和必败点都是以终结点进行逆序分析。

看到该题,我们不妨直接打表试图寻找规律。

必败点必胜点
11.411.3
11.211.1
10.3110.30
10.2910.28
10.19.30(直接转移到10.1)
9.289.29(直接转移到10.29)

解释9.28点:(1)可以一下跳到10.28,使对手处于必胜状态,(2)可以跳到9.29,对手也处于必胜状态。所以9.28为必败点。
9.29点为必胜点:存在该人报 10.29使对手处于必败状态。

必败点必胜点
9.29.1
8.318.30(直接跳到8.31,使对手必败)
8.298.28
8.38.2
8.17.31
7.307.29
7.27.1
6.30(跳到7.30)
6.296.28
6.36.2
6.15.31
5.305.29
5.25.1
.4.30(直接跳到5.30)
4.294.28
4.54.4
4.34.2
4.13.31
3.303.29
3.23.1
2.292.28
2.32.2
2.11.31
1.301.29
1.21.1
12.3112.30
12.2912.28
12.111.30(跳到12.1)
.11.29(跳到12.29)
11.2811.27

发现:

  1. 2.28是一个必胜点,2.29是一个必败点,这俩是固定的
  2. 不管是月份加一,还是日期加一,都改变了奇偶性(必胜点 月份加日期 = 偶数, 必败点两者相加为 奇数)只有两个点不同:9.30, 11.30为必胜点 例外

代码

#include <iostream>
#include <algorithm>
using namespace std;
int main(void){
    int t;
    cin >> t;
    while(t --){
        int n, y, r;
        scanf("%d%d%d", &n, &y, &r);
        if((y + r) % 2 == 0 ) puts("YES");
        else if( r == 30 && (y == 11 || y == 9)) puts("YES");
        else puts("NO");
    }
    return 0;

}

Euclid’s Game(两数关系)

题目大意

小A和小B,准备玩一个游戏,玩法是这样的,从两个自然数开始比赛。第一个玩家小A从两个数字中的较大者减去两个数字中较小者的任何正倍数,前提是得到的数字必须是非负的。然后,第二个玩家小B对得到的两个数字做同样的处理,两个玩家交替进行,直到一个玩家能够从大的数字中减去较小数字的倍数,达到0,从而获胜

分析

我们涉及到两个数,盲举自然是不太可行的。可以从两数大小关系入手
我们规定 a >= b.(不符合时,交换即可)

  1. 如果 a = b 或者 a % b = 0这两种情况对于先手都是必胜态。
  2. 当 a >= 2b, 对于先手来说, 一定可以得到 a % b 的值,
    如果 b % (a % b) = 0,后手必胜。
    先手可以把两数变成 a % b + b 和 b, 后手 只能将两数变成 a % b 和 b。先手再次处于必胜状态。
  3. b < a < 2 * b,进行模拟,直到出现必胜态,通过记录操作次数(奇偶)来判断谁赢。

代码

#include <iostream>
#include <algorithm>
using namespace std;
int a, b;
int main(void){
    while(1){
        scanf("%d%d", &a, &b);
        if(a == 0 && b == 0) break;
        if(a < b) swap(a, b);
        int cnt = 0;
        while(b){
            if(a % b == 0 || a >= 2 * b){
                cnt ++;
                break;
            }
            a -= b;
            swap(a, b);
            cnt ++;
        }
        if(cnt % 2) puts("Stan wins");
        else puts("Ollie wins");

    }
    return 0;
}

Good Luck in CET-4 Everybody!(巴什)

问题描述

Kiki和Cici打牌的时候可没忘记专业,她们打牌的规则是这样的:
1、 总共n张牌;
2、 双方轮流抓牌;
3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
假设Kiki和Cici都是足够聪明(其实不用假设,哪有不聪明的学生~),并且每次都是Kiki先抓牌,请问谁能赢呢?

分析

和巴什博弈很像,小编啊,,真的是,, 看到这题解都震惊了,,害,希望这道题能触碰到大脑里的某条神经, 从而变得聪明点。。

任何正整数都能写成若干个2的整数次方幂之和
由于规定只能取2的某个整数此方幂,只要你留给对手的牌数为 3 的倍数(3 * n)时,那你就必赢。对于每个 3 只要他取出1个(或2个)那你就 取出2个(或1个),比如剩下 8 个, 对手取出5个, 5 = 3 + 2, 那你就取出 0 + 1个, 剩下三个,必赢

代码

#include <iostream>
#include <algorithm>
using namespace std;
int main(void){
    int n;
    while(scanf("%d", &n) != EOF){
        if(n % 3) puts("Kiki");
        else puts("Cici");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xuhx&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值