zoukankan      html  css  js  c++  java
  • 【博弈论】Nim游戏

    博弈论:Nim游戏

    • Nim游戏:尼姆游戏

    Nim游戏

    内容

    给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。

    问如果两人都采用最优策略,先手是否必胜。

    概念

    必胜态

    • 在当前局面下,先手必胜的状态叫做必胜态
      • 白云和黑土在抢一张前往拉斯维加斯的飞机票,先抢到的人就有前往拉斯维加斯的机会
      • 先手的人掌握游戏的控制权。

    必败态

    • 在当前局面下,先手必败的状态叫做必败态
      • 先手的人的游戏状态完全掌握在后手的人的手中。

    基本的局面

    只存在一堆(局面一)

    先手可以直接将整堆直接拿走,让第二个人没有办法拿到任何东西

    数量相同的两堆(局面二)

    后手可以通过在先手所拿的堆相对的另外一堆中拿和先手相同的数量(跟随策略),从而能保证自己最后能拿光。

    进击的局面

    数量不同的两堆(局面三)

    • 先手可通过在两堆中数量较多的那一堆中拿出一定的数量使得两堆的数量相等,从而将当前的局面转化成局面二,局面三的先手转化成局面二的后手。

    • 相当于局面一和局面三的叠加

    结论

    每堆的数量异或,如果最终为0,则先手必输。

    • 异或的概念:相同为0,不同为1。
    • 异或运算结果为0的意思就是在博弈的过程中存在相同数量的两堆,也就是所谓的局面二。局面二是后手按照跟随策略而达到游戏的获胜的后手胜利的局面。
    • 异或运算结果为1的意思就是在博弈的过程中存在不同数量的两堆(也就是局面三)或者单单的一个堆(也就是所谓的局面一),两种的局面都是先手胜利的局面。

    题目集

    模板题AcWing 891. Nim游戏

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1E5+10;
    int stone[N];
    int main()
    {
    	int n;
    	cin>>n;
    	int ans;
    	cin>>ans;
        for(int i=2;i<=n;i++)
    	{
    	    int x;	
    	    cin>>x;
    	    ans=ans^x;
    	}	
    	if(ans==0) cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    	return 0;
    }
    

    AcWing 892.台阶-Nim游戏

    给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。

    问如果两人都采用最优策略,先手是否必胜。

    基本的局面

    只有第一级台阶拥有石子(局面一)

    此时为必胜态,直接拿完,对手就没有办法再拿了。

    只有第二级台阶拥有石子(其实可认为是全部台阶都没有任何数量的石子)(局面二)

    此时为必败态,先手者替别人打工,刚从第二级台阶拿到第一级台阶,后手者就可以把刚拿下来的石子一下子拿到地面。

    进击的局面

    只有第一级台阶和第三级台阶拥有石子,且这两级台阶上的石子数量是相等的(局面三)

    此时为必败态,先手从第一级台阶拿出多少放到地上,后手就从第三级台阶拿出多少放到第二级台阶,先不考虑接触第二级台阶上的石子。按以上操作反复进行,会发现只有第二级台阶剩下石子,也就变成了局面二(必败态)。

    只有第一级台阶和第三级台阶拥有石子,且这两级台阶上的石子数量是不等的(局面四)

    此时先手可在第一级台阶和第二级台阶中的拥有更多的石子的那个台阶拿出一定数量的石子使得两个台阶的石子数量相等(局面三),而此时局面四的先手将转化为局面三的后手(局面三是后手胜利)。

    只有第2k+1级和2k+3级台阶上拥有石子(局面五)

    根据跟随策略,可将局面五转化成局面三或者局面四。

    偶数级的台阶上的石子

    可转换为局面二,可以忽略掉偶数级台阶的石子。

    结论

    台阶-Nim游戏可当作是只考虑奇数级台阶的普通版本的Nim游戏

    奇数堆的数量异或,如果最终为0,则先手必输。

    • 代码
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1E5+10;
    int stone[N];
    int main()
    {
    	int n;
    	cin>>n;
    	int ans;
    	cin>>ans;
        for(int i=2;i<=n;i++)
    	{
    	    int x;	
    	    cin>>x;
    	    if(i&1)ans=ans^x;
    	}	
    	if(ans==0) cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    	return 0;
    }
    

    其他

    • Impartial 公平的
  • 相关阅读:
    多线程实践
    sql你server,mysql,oracle的分页语句
    BS与CS的联系与区别
    EJB与JAVA BEAN的区别
    Struts2.0 xml文件的配置(package,namespace,action)
    Q 51~60
    Q 41~50
    列表推导式
    Q 31~40
    Q 21~30
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/15100342.html
Copyright © 2011-2022 走看看