zoukankan      html  css  js  c++  java
  • 博弈论中的尼姆博弈

    尼姆博奕(Nimm Game):有三堆各若干个物品,两个人轮流从某一堆取任意多的
    物品,规定每次至少取一个,多者不限,最后取光者得胜。

        这种情况最有意思,它与二进制有密切关系,我们用(a,b,c)表示某种局势,首先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局势是(0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0)。仔细分析一下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n,n)的情形。

        计算机算法里面有一种叫做按位模2加,也叫做异或的运算,我们用符号(+)表示这种运算。这种运算和一般加法不同的一点是1+1=0。先看(1,2,3)的按位模2加的结果:

    1 =二进制01
    2 =二进制10
    3 =二进制11 (+)
    ———————
    0 =二进制00 (注意不进位)

        对于奇异局势(0,n,n)也一样,结果也是0。

        任何奇异局势(a,b,c)都有a(+)b(+)c =0。

    如果我们面对的是一个非奇异局势(a,b,c),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c 变为 a(+)b,即可,因为有如下的运算结果: a(+)b(+)(a(+)b)=(a(+)a)(+)(b(+)b)=0(+)0=0。要将c 变为a(+)b,只要从 c中减去 c-(a(+)b)即可。

        例1。(14,21,39),14(+)21=27,39-27=12,所以从39中拿走12个物体即可达到奇异局势(14,21,27)。

        例2。(55,81,121),55(+)81=102,121-102=19,所以从121中拿走19个物品
    就形成了奇异局势(55,81,102)。

        例3。(29,45,58),29(+)45=48,58-48=10,从58中拿走10个,变为(29,4

    5,48)。


    链接:

    http://acm.hfut.edu.cn/OnlineJudge/  (2014京胜杯D题)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn=10001;
    int a[maxn];
    int main()
    {
        int n;
        while(cin>>n)
        {
            int sum=0;
            for(int i=0;i<n;i++)
            {
                cin>>a[i];
                sum^=a[i];
            }
            if(sum==0)
                cout<<"No"<<endl;
            else
                cout<<"Yes"<<endl;
        }
        return 0;
    }
    


    如果我们面对的是一个非奇异局势(a,b,c),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c 变为 a(+)b,即可,因为有如下的运算结果: a(+)b(+)(a(+)b)=(a(+)a)(+)(b(+)b)=0(+)0=0。要将c 变为a(+)b,只要从 c中减去 c-(a(+)b)即可。

        例1。(14,21,39),14(+)21=27,39-27=12,所以从39中拿走12个物体即可达到奇异局势(14,21,27)。

        例2。(55,81,121),55(+)81=102,121-102=19,所以从121中拿走19个物品
    就形成了奇异局势(55,81,102)。

        例3。(29,45,58),29(+)45=48,58-48=10,从58中拿走10个,变为(29,4
    5,48)。


    链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=1850


    可选步数为任意步,SG(x) = x; 
    本题中每一堆都可以选任意个,所以每一堆的SG值都是所剩余的个数。
    最后结果是所有堆的SG值异或的结果。令ans = 所有堆的SG值异或的结果
    如果ans == 0,则是必败点。
    如果ans != 0,使取后结果为0的策略是必胜策略
    具体怎么取呢?
    每一堆的数值与ans相异或,所得的结果就是这一堆可以取的数量。
    但是,如要这一堆数量没有这么多,就不可以这么取


    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=101;
    int a[maxn];
    int main()
    {
        int n;
        while(cin>>n)
        {
            if(n==0)
                break;
                int sum=0;
            for(int i=0;i<n;i++)
            {
                cin>>a[i];
                sum^=a[i];
            }
            int ans=0;
            for(int i=0;i<n;i++)
            {
                if(a[i]>(sum^a[i]))
                    ans++;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    


    取火柴游戏

    链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=1907

    题意:n堆火柴,2人每次从任意一堆中取至少1个,也可以将整堆取玩,取得最后一根火柴的人输

    定义:若所有火柴数异或为0,则该状态被称为利他态,用字母T表示;否则, 为利己态,用S表示。

    [定理1]:对于任何一个S态,总能从一堆火柴中取出若干个使之成为T态。

    [定理2]:T态,取任何一堆的若干根,都将成为S态。

    [定理 3]:S态,只要方法正确,必赢。

    [定理4]:T态,只要对方法正确,必败。


    接着来解决第二个问题
    定义:若一堆中仅有1根火柴,则被称为孤单堆。若大于1根,则称为充裕堆。
    定义:T态中,若充裕堆的堆数大于等于2(若充裕堆数为1,则最后异或一定不为0 ,因为高位只有一个1,异或结果一定不为0),则称为完全利他态,用T2表示;若充裕堆的堆数等于0,则称为部分利他态,用T0(说明孤单堆的数目一定是偶数,否则异或结果定不为0,且因为是偶数,后拿的一定会最后取光所有物品,在第二个问题中先拿的是赢家)表示。


    孤单堆的根数异或只会影响二进制的最后一位,但充裕堆会影响高位(非最后一位)。一个充裕堆,高位必有一位不为0,则所有根数异或不为0。故不会是T态。

    [定理5]:S0态,即仅有奇数个孤单堆,必败。T0态必胜。 

    [定理6]:S1态( 一堆充裕堆,x个孤单堆),只要方法正确,必胜。 

    证明:
    若此时孤单堆堆数为奇数,把充裕堆取完 , 变成S0;

    否则有偶数个孤单堆,将充裕堆取得剩一根。这样,就变成奇数个孤单堆即
    S0,由对方取。

    由定理5 ,必胜。

    [定理7]:S2态不可转一次变为T0态。

    [定理8]:S2态可一次转变为T2态。 

    (若充裕堆>2 (1:充裕堆为偶数,孤单堆为奇数,将一个孤单堆取完),(2:充裕堆为奇数,若孤单堆为偶数,则取完一个充裕堆,若孤单堆为奇数,则取得一个充裕堆剩1个。))

    [定理9]:T2态,只能转变为S2态或S1态。(
    若充裕堆>2则可转变为S2 ,若充裕堆=2,则可转变为S1
    )。

    [定理10]:S2态,只要方法正确,必胜.

    证明:
    方法如下: 
          1)  S2态(),就把它变为T2态()。(由定理8) 
          2)  对方只能T2转变成S2态或S1态((定理9)
               若转变为S2,  转向1) 
               若转变为S1(),  这己必胜。(定理5)

    定理11]:T2态必输。

    综上所述,若是 
      S2,S1,T0 。 则先下的人必胜。

                      若是 
     T2,S0 。则先下的人必输。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=101;
    int a[maxn];
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            int n;
            cin>>n;
            int ans=0;
            int sum1=0;
            int sum2=0;
            for(int i=0;i<n;i++)
            {
                cin>>a[i];
                if(a[i]>=2)
                    sum1++;
                else
                    sum2++;
                ans^=a[i];
            }
            if((ans!=0&&sum1>0)||(ans==0&&sum1==0))
                cout<<"John"<<endl;
            else if((ans!=0&&sum1==0)||(ans==0&&sum1>1))
                cout<<"Brother"<<endl;
        }
        return 0;
    }
    

     链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=2509

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=101;
    int a[maxn];
    int main()
    {
        int n;
        while(cin>>n)
        {
            int ans=0;
            int sum=0;
            for(int i=0;i<n;i++)
            {
                cin>>a[i];
                if(a[i]>1)
                    sum++;
                ans^=a[i];
            }
            if((ans!=0&&sum>0)||(ans==0&&sum==0))
                cout<<"Yes"<<endl;
            else if((ans==0&&sum>1)||(ans!=0&&sum==0))
                cout<<"No"<<endl;
        }
        return 0;
    }
    


  • 相关阅读:
    hi.baidu.com 百度流量统计
    Autofac is designed to track and dispose of resources for you.
    IIS Manager could not load type for module provider 'SharedConfig' that is declared in administration.config
    How to create and manage configuration backups in Internet Information Services 7.0
    定制swagger的UI
    NSwag在asp.net web api中的使用,基于Global.asax
    NSwag Tutorial: Integrate the NSwag toolchain into your ASP.NET Web API project
    JS变量对象详解
    JS执行上下文(执行环境)详细图解
    JS内存空间详细图解
  • 原文地址:https://www.cnblogs.com/wolf940509/p/6617119.html
Copyright © 2011-2022 走看看