Mastermate官网 香港|英国|新加坡|澳大利亚|澳门|深圳硕士研究生申请平台

暑假训练专题一 博弈

一:巴什博弈:

acm 例题 北京师范大学oj:http://oj.51isoft.com/contest/problem_show.php?pid=23384

 

post code:

#include<stdio.h>
int main()
{
   int n,num,m;
   scanf("%d",&n);
   while(n--)
   {
     scanf("%d %d",&num,&m);
     if(num<=m)printf("player1 wins\n");
     else {
            if(num%(m+1)==0)printf("player2 wins\n");
            else printf("player1 wins\n");
          }          
   }    
}

 

n只有一堆n 个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m 个。最后取光者得胜。
n给你n,如何判断先手还是后手赢
 
n显然如果n<=m,先取者胜。
n显然,如果n=m+1,那么由于一次最多只能取m 个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜
 
因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r 为任意自然数,s≤m),那么先取者要拿走s 个物品,如果后取者拿走k(k≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)*(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜
二:威佐夫博弈
n有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
 

必死局的判定:

如果 a遇到了6,10 ,须变化一次,只能对角线,竖着,横着变化。

b仅一次就可以将其变化成为 图中的死局。

因为 在(6,10)之前含有 (1,2)(3,5)(4,7) 横纵都包含了 1-5,向上和往对角线方向都被封死了,都可以转化到这三个数。

只能横着走:

但会被(1,1)(1,2)(3,5)(4,7)对角线封锁,

例如 a遇到(6,10) 竖向变成(3,10),因为包含数字3,则可以转化为(3,5);a将又一次面临死局。

                            横向变成(6,8),在(3,5)的对角线上,所以可以直接的转化成(3,5);

                            横向变成(6,6),a直接两个都减去6,致使b输掉了。

必死局的判定:死局的前几项是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10(8,13)、(9,15)、(11,18)、

(12,20)
n我们总结了如下公式:ak =[k(1+√5)/2],bk= ak + k (k=0,1,2,...,n 方括号表示取整函数)
即成立;
威佐夫博弈  博弈分为 必死局和非必死局
 必死局的判定:
n任何自然数都包含在一个且仅有一个在必死局势中。
n2、任意操作都可将必死局变为非必死局势。
n3、采用适当的方法,可以将非必死局势变为必死局势。
 
三:尼姆博弈
求出  
n尼姆博奕(Nimm Game):
n对于任何局势(a1, a2,..,..,..,an)
na1(+)a2(+)…(+)an .  ( (+)为 按位与)结果为0则先手输,否则先手赢
 
n另一种题目:
n给出n堆石头的数目,若先手赢问第一步可行的方案数是多少?
n以(7,8,9)为例:
n7----       0111
n8----       1000
n9----       1001
n        ————
n               0110(6)结果不为0,先手赢
n第一步方案数为1. 
即看^(所有元素异或后的结果)。
中的第一次出现“1”的位数
例如上式,的出的结果为6,出现“1”的次数是第三位,则看7,8,9,中第三位存在几个‘1’,就是最后的方案数。上述只有7,有‘1’,所以方案数为1.
要注意的是,这样判断的结果是      根据 8,9的性质来决定的。
1:判断 取出的个数是 8^9=(7^8^9)^7
使得7变成 (8^9)这样是三个数异或的结果为0;
2:  注意的是 异或后的结果 必须小于 7,这样才成立;
 
下面是关于异或的性质:
1. a ^ b = b ^ a
2. a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;
3. d = a ^ b ^ c                                     可以推出 a = d ^ b ^ c.
4. a ^ b ^ a = b.
 
下面推荐一道杭电上的题: 加深理解:http://acm.hdu.edu.cn/showproblem.php?pid=2176
post code:
#include<stdio.h>
int main()
{
  int n,i,a[200010],num,j;
  while(scanf("%d",&n)&&n!=0)
  {   i=1;
      scanf("%d",&num);
      a[i]=num;
      for(i=2;i<=n;i++)
      {
         scanf("%d",&a[i]);
         num=num^a[i];               
      }                       
      if(num==0)printf("No\n");
      else {
            printf("Yes\n");
             for(i=1;i<=n;i++)
             {
             if(a[i]>(a[i]^num))   printf("%d %d\n",a[i],a[i]^num);            
             }   
           }
  }    
}

算法描述:判断他们的异或是否为0;

为0则成立;

不为0 输出你要取出的值,即每个元素遍历一遍,找出  其他值异或小于他的结果,然后进行输出:这样就得出了正确答案。

 
 自己想了半天:弄懂这道题的解法,挺有意思的:
大家可以参考一下:
这道题:主要是按一下方式进行描述:
如果(b%a,a)是一个必胜态,那就要看b/a的值,如果b/a>1,那么先手可以由状态(a,b)到达(a,b%a+a),这样后手就只能到达(b%a,a),所以此时(a,b)仍然是一个必胜态;如果b/a=1,那么先手只能到达(b %a,a),因此(a,b)就是一个必败态. 
上面这句话是关键: 在不断得寻找找必败态和必胜态, 将其赋值给给出的初始数据,最后的到自己想要的结果。
 
post code:
#include<stdio.h>
void swap(int &a,int &b);
int fun(int a,int b);
int main()
{
    
    int a,b,result;
    while(scanf("%d %d",&a,&b)&&(a!=0||b!=0)) 
    {
      if(a<b)swap(a,b);              
      result=fun(a,b);             //寻找输入数据的状态。
      if(result==1)printf("Stan wins\n");
      else printf("Ollie wins\n");          
    }   
}


void swap(int &a,int &b)
{
  int temp;
  temp=a;
  a=b;
  b=temp;     
}

int fun(int a,int b)
{
   if(a%b==0)return 1;  
   else {if( fun(b,a%b)&&(a/b==1) )   对于其中的定量描述;就如同上面所描述的。
             return 0 ;   
         else return 1; 
         }
}


 
posted @ 2012-06-30 16:52  大嘴鸟  阅读(208)  评论(0编辑  收藏  举报
Mastermate官网 香港|英国|新加坡|澳大利亚|澳门|深圳硕士研究生申请平台