简单博弈论

 

1.巴什博弈

问题描述一般为,有一堆物品,有N个,A、B轮流从中取物,最少取一个,最多取m个,规定取走最后一堆的人获胜。

对于博弈问题,首先需要分析的是它的必败情况。由题目可知,假设当前的人A面对的物品堆已空,即为0时,就输了,所以最基本的必败为0。那么根据取物品的取值为1~m,可以知道,在上一步B取物的时候,那一堆只剩下1~m个了,根据两人都采取最优策略的原则,A在可能的情况下绝对不会让B遇到1~m这种情况,除非当前A遇到的那一堆是1+m个的,而自己必须至少取一个,才会导致这种局面。换言之,如果初始的时候,N%(m+1)==0,那么每当先手取走k,后手都可以通过取m+1-k使得先手再次面临N%(m+1)==0的必败局面。因此只要N%(m+1)==0 则先手必败,否则 当N%(m+1)==k  【通过取余可知 k<=m】时,先手都可以通过取走k个使得后手面临N%(m+1)==0的必败局面

一个类似的变相问题:两个人轮流报数,每次至少报一个,至多报m个,报到第N个者胜。

推荐:hdu 1846,2147,2149,2188。

P/N图分析:  P表示必败点 遇到该点局势的人必败  N表示必胜点 遇到该点局势的人必胜  注:前提是两者都不失误

对于P点来说,他的每一个下一个承接状态都是必胜点N。对于N点来书,他的每一个下一个承接状态中至少有一个P。

那么图的终结点,也就是结束状态,为P的,因为无论谁面对这个状态都是输。然后逆向推导即可。注意从边界开始推。

 

 

2.斐波那契博弈

一堆个数为N的石子,轮流取石。

规定:1.先手不能一次取完

          2.如果上一个人取了x,那么现在这个人可以取1·~2*x

 

 

介绍一个定理:齐肯多夫定理:任何正整数都可以被分解为任意个不连续(注意不连续很重要)的斐波那契数之和。

对于斐波那契来说,F[i]=F[i-1]+F[i-2],那么如果是两个不连续的斐波那契的话,也就是最接近的情况为F[i]和F[i-2],而F[i]=F[i-1]+F[i-2],因为F[i-1]>F[i-2],所以F[i]>2*F[i-2];这里出现了两倍,于是联想到了斐波那契博弈的要求,取的数量为1~2*x。(解释乱七八糟:暂时自己也想不通,先记一下结论)

 

 

所以将一开始的整数分解为若干个不连续的斐波那契数列和(分成多个堆),由于不连续斐波那契的F[i]>2*F[i-2]关系,因此如果一开始的数是一个斐波那契数的话,那么A必须是在后手才能取走最后一个。而如果他不是一个斐波那契数的话,那么A可以先手取走K使得对手面临一个斐波那契数。

因此结论:如果一开始是斐波那契,则后手赢,如果一开始不是斐波那契,则先手赢。即面对斐波那契数的人必输。

 

 

 

3.威佐夫博弈  证明需要用到betty定理

问题描述:有两堆物品,各为若干个,两个轮流任意从其中一堆或者同时从两堆中取相同的任意个(可以至少把一堆取完)。每次至少取一个,取光者胜。

分析:用(ai,bi)表示局势(两堆各自的数量),当A面对(0,0)时,A必输,称此为奇异局势。列举出前几个奇异局势,为(0,0),(1,2)

(3,5),(4,7),(5,9)

规律为  ai为之前的局势中没有出现的第一个数,bi=ai+i。

奇异局势有的性质:

1.任何自然数仅仅包含在一个奇异局势中

ak>ak-1  由于 bk=ak+k>ak-1+k-1=bk-1>ak-1

 

 

 

2.任意操作都可以将奇异局势变为非奇异局势

1)如果当前局势为(x,y)  如果选择改变其中一个分量,那么由于另外一个分量不变,所以不可能变为另外一个奇异局势。

 

 

 

2)如果x,y同时改变,由于其差值不变,因此也不会变为另一个奇异局势。

 

 

 

3.用适当的方法可以将非奇异局势变为奇异局势

 

 

 

结论:对于一个奇异局势(ak,bk)  我们可以发现  ak=k*(sqrt(5)+1)/2  【黄金分割比】  而bk=ak+k 

因此 如果(bk-ak)* (sqrt(5)+1)/2 =ak,那么就是奇异局势(必败局势)。

#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
 int a,b;
 while(scanf("%d%d",&a,&b)!=EOF)
 {
  if(a>b)
  {
   int t=a+b;
   a=t-a;
   b=t-a;
  }
  int c=b-a;
  if(a==(floor((sqrt(5.0)+1)/2*c)))
  {
   printf("0\n");
  }
  else
  { 
   printf("1\n");
  }
 } 
 return 0;
}

 

 

4.妮姆博弈

问题描述:N堆物品,两个人轮流从某一堆中取任意多的物品。

三堆的妮姆博弈的基本奇异局势(0,0,0)  (0,n,n)   对于第二个来说,如果当前者在某一堆中取了x,另一个人可以在另一堆中取x使得第一个人再次面对 (0,n,n) 。所以可以猜测,妮姆博弈的奇异局势的特点为,每堆个数抑或起来结果为0。如果不为0的话,假设前n-1堆抑或的结果为x,只要将最后一堆变为x就可以了。

结论:抑或结果为0是奇异局势,面对其者必败。

妮姆博弈-阶梯博弈

蓝桥杯 高僧斗法  

时间限制:1.0s   内存限制:256.0MB

      

问题描述

  古时丧葬活动中经常请高僧做法事。仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
  节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。又有若干小和尚随机地“站”在某个台阶上。最高一级台阶必须站人,其它任意。(如图1所示)
  两位参加游戏的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
  两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
  对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。

输入格式

  输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N<100, 台阶总数<1000)

输出格式

  输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。若有多个解,输出A值较小的解,若无解则输出-1。

样例输入

1 5 9

样例输出

1 4

样例输入

1 5 8 10

样例输出

1 3

说一些似懂非懂的理解......

首先这个题目,可以把它抽象成取球模型。

想法1:最高层的人对应的堆个数为0,第二层对应的堆的个数为和上一层高度差-1(题目要求同台阶不站人)。于是我们可以把题目看成取这些堆,每次拿走任意多个,变成一个一般的尼姆博弈问题。然而( ° △ °|||)。。。我们忽略了一点,题目要求下层的人不能越过上层的人,而一般的取球模型并没有这个约束(堆之间的大小关系不能变动),如果把模型抽象成这样,对我们每次取球的个数加上了限制。( ̄ε(# ̄) 

想法2:我们回想一下一般的妮姆博弈在两堆时候的情况,如果两堆大小相等,后手只需要模仿先手就可以赢得胜利,而如果两堆大小不等,先手可以将大的取成和小的一样,然后模仿后手的行为就能取胜。

在上图中,我们可以将A-B、C-D间的距离当成尼姆堆:

A.如果当前是奇异局势,先手将B上移x,那么后手可以追随将A上移x,使得先手再度面临奇异局势。如果先手将A上移动,我们也可以将C上移使得最后抑或出来结果依旧为0,依旧是奇异局势。

B.如果不是奇异局势,那么先手让后手面临奇异局势即可胜利。

总之分析问题不要太重过程,在上述分析中我们并没有深刻地讨论具体移动的步骤,我们只是抽象出了那些会影响胜负的因素罢了。

AC代码:

#include<iostream>
using namespace std;
int Arr[105],Rest[105];
int main(){
    int n=1,i,j,res=0,temp,cnt;
    while(cin>>Arr[n]){
        n++;
    }
    n--;//总数
    for(i=2;i<=n;i+=2){
        Rest[i/2]=Arr[i]-Arr[i-1]-1;
        res^=Rest[i/2];
    }
    if(!res){
        cout<<-1;
    }
    else if(n<=3){
        cout<<Arr[1]<<" "<<Arr[2]-1;
    }
    else{
        for(i=1;i<n;i++){
            for(j=1;Arr[i]+j<Arr[i+1];j++){//i为奇数  尼姆堆变小   否则尼姆堆变大
                cnt=(i+1)/2;
                res^=Rest[cnt];
                temp=(i&1?Rest[cnt]-j:Rest[cnt]+j);
                res^=temp;
                if(!res){
                    cout<<Arr[i]<<" "<<Arr[i]+j;
                    break;
                }
                res^=temp;
                res^=Rest[cnt];
            }
        }
    }
    return 0;
}

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值