博弈

首先,先拿一个例题介绍一下巴什博弈。(Bash Game)

最重要的公式n%(m+1)==0先手必败否则后手必败

 

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

 

像这样2人采用最优策略取石子的问题就是典型的巴什博弈的思想

 

假设一开始有n个石子那么n一定可以写成n=(m+1)*r+s的形式,既然这样的话,假如A先取,那么一开始A取走s个石子(s<m),之后B取走k个石子,所以说,假如A再取走m+1-k个石子,之后就剩余(m+1)*(r-1)个石子给B下一次取,也就是说如果不断取下去,最终该B取的时候还有(m+1)*1个石子,B不论拿走几个,A下一次都可以一次取完,所以说,当s=n%(m+1)中,s>0的时候,为A的必胜态     

 

   if(n%(m+1)==0)  
            printf("second\n");  
        else  
          printf("first\n");  

http://acm.hdu.edu.cn/showproblem.php?pid=2149(巴什博弈的推广)

加价在(1-N)之间物品价值低价M只要有人加价大于等于M就赢了

分三种情况

1.M<=N,直接便利从M到N。

2.M%(N+1)==0后手获胜

3.M%(N+1)>0先手可以初始拿从(1-N)获胜

if(m<=n)

        {

            for(int k=m;k<=n;k++)

            {

                if(k==m)

                    printf("%d",k);

                else

                    printf(" %d",k);

            }

            printf("\n");

            continue;

        }

        if(m%(n+1)>=1)

        {

            int flag=0;

            for(int k=1;k<=n;k++)

            {

                if((m-k)%(n+1)==0)

                {

                    if(flag==0)

                        printf("%d",k);

                    else

                        printf(" %d",k);

                    flag=1;

                }

            }

            printf("\n");

        }

        else

            printf("none\n");

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

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

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

 

 

分析此类问题主要放法是:P/N分析:

 

    P点:即必败点,某玩家位于此点,只要对方无失误,则必败;

    N点:即必胜点,某玩家位于此点,只要自己无失误,则必胜。

     三个定理:

    一、所有终结点都是必败点P(上游戏中,轮到谁拿牌,还剩0张牌的时候,此人            就输了,因为无牌可取);

   二、所有一步能走到必败点P的就是N点;

   三、通过一步操作只能到N点的就是P点;

P-N图中只要m,n分别是P-N图中的行列(m%2==1&&n%2==1)

先手必败,否则后手必败。

 

威佐夫博弈(Wythoff Game)


有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。



直接说结论了,若两堆物品的初始值为(x,y),且x<y,则另z=y-x;



记w=(int)[((sqrt(5)+1)/2)*z  ];



若w=x,则先手必败,否则先手必胜。


问题:首先有两堆石子,博弈双方每次可以取一堆石子中的任意个,不能不取,或者取两堆石子中的相同个。先取完者赢。

分析:首先我们根据条件来分析博弈中的奇异局势

     第一个(0 , 0),先手输,当游戏某一方面对( 0 , 0)时,他没有办法取了,那么肯定是先手在上一局取完了,那么输。

第二个 ( 1  , 2  ),先手输,先手只有四种取法,

1)取 1 中的一个,那么后手取第二堆中两个。

2)取 2 中一个,那么后手在两堆中各取一个。

3)在 2 中取两个,那么后手在第一堆中取一个。

4)两堆中各取一个,那么后手在第二堆中取一个。

可以看出,不论先手怎么取,后说总是能赢。所以先手必输!

第三个 ( 3 , 5 ),先手必输。首先先手必定不能把任意一堆取完,如果取完了很明显后手取完另一堆先手必输,那么

假如看取一堆的情况,假设先手先在第一堆中取。 取 1 个,后手第二堆中取4个,变成(1 ,2)了,上面分析了是先手的必输局。

 取 2 个,后手第二堆中取3个,也变成( 1 , 2)局面了。

假设先手在第二堆中取,取 1 个,那么后手在两堆中各取 2 个,也变成 ( 1 , 2 )局面了。

   取 2 个 ,那么后手可以两堆中都去三个, 变成 ( 0 , 0)局面,上面分析其必输。

   取  3  个,后手两堆各取 1 个 ,变成( 1 , 2)局面了。

  取 4 个,后手在第一堆中取一个,变成( 1 , 2)局面了。

可见不论先手怎么取,其必输!

第四个(4  , 7),先手必输。

自己推理可以发现不论第一次先手如何取,那么后手总是会变成前面分析过的先手的必输局面。

那么到底有什么规律没有呢,我们继续往下写。

第四个 ( 6 ,10  )

第五个 ( 8 ,13)

第六个 ( 9 , 15)

第七个 ( 11 ,18)

会发现他们的差值是递增的,为 0 , 1 , 2, 3, 4 , 5 , 6, 7.....n

而用数学方法分析发现局面中第一个值为前面局面中没有出现过的第一个值,比如第三个局面,前面出现了 0  1 2,那么第三个局面的第一个值为 3 ,比如第五个局面,前

面出现了 0  1  2 3 4 5 ,那么第五个局面第一个值为6。

再找规律的话我们会发现,第一个值 = 差值 * 1.618 

而1.618 = (sqrt(5)+ 1) /  2 。

大家都知道0.618是黄金分割率。而威佐夫博弈正好是1.618,这就是博弈的奇妙之处!

 

 

下面来看看威佐夫博弈常见的三类问题:

 

1)给你一个局面,让你求是先手输赢。

(判断是否是奇异局势;方法(x,y)中x<y;若x==(sqrt(5)+ 1) /  2 *(y-z)则先手必败

有了上面的分析,那么这个问题应该不难解决。首先求出差值,差值 * 1.618 == 最小值 的话后手赢,否则先手赢。(注意这里的1.618最好是用上面式子计算出来的,否则精

度要求高的题目会错)

 

2)给你一个局面,让你求先手输赢,假设先手赢的话输出他第一次的取法。

       首先讨论在两边同时取的情况,很明显两边同时取的话,不论怎样取他的差值是不会变的,那么我们可以根据差值计算出其中的小的值,然后加上差值就是大的一个值,当

然能取的条件是求出的最小的值不能大于其中小的一堆的石子数目。

      加入在一堆中取的话,可以取任意一堆,那么其差值也是不定的,但是我们可以枚举差值,差值范围是0 --- 大的石子数目,然后根据上面的理论判断满足条件的话就是一种合理的取法。

 

 

输入所有的P点 http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=837

 http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=161

模板题

第一种的解:

 long long temp=max(a,b)-min(a,b);

        long long temp1=(sqrt(5)+1)/2.0*temp;

第二种解的模板:例题:http://acm.hdu.edu.cn/showproblem.php?pid=2177


 

int vis[1000005]; 

long long  wzf(long long x,long long  y)

{

    int t=max(x,y)-min(x,y);

    long long temp=(sqrt(5)+1)/2.0*t;

    if(temp==min(x,y))

        return 0;

    else

        return 1;

} 

void display(int x,int y)

{

    if(vis[x]==0 || vis[y]==0)

    {

        vis[x]=1;

        vis[y]=1;

        if(x<=y)

            printf("%d %d\n",x,y);

        else

            printf("%d %d\n",y,x);

    }

}

int main()

{

    long long a,b;

    while(scanf("%lld%lld",&a,&b)!=EOF)

    {

        memset(vis,0,sizeof(vis));

        if(a==0 && b==0)

            break;

        if(wzf(a,b)==0)

            printf("0\n");

        else

        {

            printf("1\n");

            for(long long k=a,kk=b;kk>=0 && kk>=0;k--,kk--)

            {

                if(wzf(k,kk)==0)

                    display(k,kk);

            }

          

            long long t=max(a,b);

            for(long long k=0;k<=t-1;k++)

            {

                if(wzf(min(a,k),max(a,k))==0)

                {

                    display(min(a,k),max(a,k));

                }

            }

        }

    }

    return 0;

 } 

 

尼姆博弈


尼姆博弈指的是这样一个博弈游戏:有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。



结论就是:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。

模板如下:

#include <cstdio>  
#include <cmath>  
#include <iostream>  
using namespace std;  
int main()  
{  
    int n,ans,temp;  
    while(cin>>n)  
    {  
        temp=0;  
        for(int i=0;i<n;i++)  
        {  
            cin>>ans;  
            temp^=ans;  
        }  
        if(temp==0)  cout<<"后手必胜"<<endl;  
        else cout<<"先手必胜"<<endl;  
    }  
    return 0;  
}

 

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值