0
点赞
收藏
分享

微信扫一扫

信息学奥赛一本通 1218:取石子游戏 | OpenJudge 2.5 6266:取石子游戏

boomwu 2022-04-24 阅读 44
c++

【题目链接】

ybt 1218:取石子游戏
OpenJudge 2.5 6266:取石子游戏

【题目考点】

1. 博弈:完全信息博弈

博弈树:
博弈树的结点对应于某一个棋局,其分支表示走一步棋;根部对应于开始位置,其叶表示对弈到此结束。在叶节点对应的棋局中,竞赛的结果可以是赢、输或者和局 。
如果该博弈为完全信息博弈,那么博弈双方都清楚整个博弈树,那么该游戏在开始前即可确定先手必胜/必败/或最好情况只能是平局。
博弈树的每一个结点有三种标识:w(对应于赢)、d(对应于和局)或者l(对应于输)。
如果当前的棋局是标有w的,那么此时先手有必胜策略。如果结点标识为d,那么除非对手失误,否则先手最好的情况也只能达成和局;如果结点标识为l ,那么无论先手如何下,对手都有必胜策略。
确定各结点标识的方法如下:
首先,叶子结点标识棋局结束,可以很多容易地判定叶子结点的标识。
如果该结点的子结点都是w,那么说明自己走一步棋后,对手总有必胜策略,那本结点对应的棋局先手必输,标记为l。
如果该结点的子结点存在l,那么自己走一步棋后,棋局变为标记为l的结点,对手输,自己胜。所以本结点标记为w。
如果该结点的子结点不存在l,但存在d,那么自己走一步棋后,棋局变为标记为d的结点,可以争取到平局,本结点标记为d。
按此方法标记每个结点。
如果根结点标记为w,那么先手有必胜策略。如果根结点标记为l,那么后手有必胜策略。如果根结点标记为d,那么先手有至少达到和局的策略。

【解题思路】

1. 建立博弈树

两堆石子数目确定后,构成一种棋局,在双方都不犯错误的情况下,先手必胜或必败。
根据题意,画出测试用例对应的博弈树:
在这里插入图片描述

先画出剩下两堆石子个数可能的变化,再确定标记。
在(2,10)时,此时先手可以做到在10中拿2的5倍,将第2堆拿完,取得胜利,所以此处标记为w。(2,10)的父结点(10,12)自然为l。而(10,12)的父结点自然为w。
对于输入(15,24),可以得到博弈树:
在这里插入图片描述
进而得知先手必输。

2. 证明题目中的提示

证明:如果 ⌊ a b ⌋ < 2 \lfloor \frac{a}{b} \rfloor < 2 ba<2,那么先手只有唯一的一种取法。

证明:假设石子数目为(a,b)且 a ≥ b a \ge b ab,如果 ⌊ a b ⌋ ≥ 2 \lfloor \frac{a}{b} \rfloor \ge 2 ba2则先手必胜。

3. 编码

设递归函数bool dfs(int a, int b),意为当两堆石子分别是(a,b),且 a ≥ b a\ge b ab,时先手是否必胜。

  • 如果当前两堆石子a是b的倍数,那么先手可以直接拿光a,本轮先手必胜。
  • ⌊ a b ⌋ ≥ 2 \lfloor \frac{a}{b} \rfloor \ge 2 ba2即整除运算a/b >= 2,那么本轮先手必胜。
  • 否则本轮只能有一种取法,就是在a中取走b,剩下两堆石子为(b, a-b),其中 b ≥ a − b b \ge a-b bab。下一轮先手必胜的情况为dfs(b, a-b),如果下一轮先手必胜,那么本轮先手必败。如果下一轮先手必败,那么本轮先手必胜。所以下一轮的先手必胜情况与本轮相反,所以本轮的先手必胜情况为!dfs(b, a-b)

【题解代码】

解法1:博弈 递归

#include <bits/stdc++.h>
using namespace std;
bool dfs(int a, int b)//a:较多一堆石子的数量 b:较少一堆石子的数量  返回:此时是否先手必胜 
{
    if(a%b == 0)
        return true;//一堆是另一堆的整数倍,此时先手一定可以拿光一堆获得胜利。
    if(a/b >= 2)//如果floor(a/b)>=2,那么先手必胜 
        return true;
    else
        return !dfs(b, a-b);//下一轮先手是否必胜的情况为dfs(b, a-b),本轮先手的获胜情况与之相反。 
}
int main()
{
    int a, b;
    while(cin >> a >> b)
    {
        if(a == 0 && b == 0)
            break;
        if(a < b)
            swap(a, b);//保证a较大,b较小 
        cout << (dfs(a, b) ? "win" : "lose") << endl;
    }
    return 0;
}
举报

相关推荐

0 条评论