经典博弈算法三大模板

转自:http://colorfulshark.cn/wordpress/巴氏(bash)威佐夫(wythoff)尼姆(nim)博弈之模板-823.html

最近研究了一下博弈论(听起来很高大上),当然,这只是博弈论中的冰山一角,但不可否认,巴氏(bash)博弈,威佐夫(Wythoff)博弈和尼姆(Nim)博弈这三种在ACM比赛中也是相当重要的,而最大的问题就是,博弈理解起来有较大的难度,即使理解了,也很难快速转换成代码,这对于做题来说是很不利的,于是,我就决定写一套模板,包括多一点接口,从而方便以后的使用,当然,虽然说是自己写的,但也是参考了别人的代码,所以别告我侵权哈。大笑


首先是Bash(巴氏)博弈,这是比较简单的一种,原理就不解释了,相信大家都懂,代码很简短,只需要输入这一堆石子的数目,输赢立刻见分晓


  1. #include<iostream>   
  2. using namespace std;   
  3. int main(void)   
  4. {   
  5.     int cas,total,price;   
  6.     scanf("%d",&cas);   
  7.     while(cas--)   
  8.     {   
  9.         scanf("%d%d",&total,&price);   
  10.         if(total%(price+1))   
  11.             cout<<"先手赢"<<endl;   
  12.         else   
  13.             cout<<"先手输"<<endl;   
  14.     }   
  15.     return 0;   
  16. }   


接下来上威佐夫(Wythoff)博弈,石子变成两堆,难度也大幅提升,但是

  1. #include<iostream>  
  2. #include<cmath>  
  3. #include<stdio.h>  
  4. using namespace std;  
  5. int main ()  
  6. {  
  7.     int a,b,dif;  
  8.     double p=(sqrt((double)5)+1)/double(2);  
  9.     while(cin>>a>>b)  
  10.     {  
  11.         dif=abs(a-b);//取差值  
  12.         a=a<b?a:b;//取较小的值  
  13.         if(a==(int)(p*dif))//判断是不是奇异局势  
  14.             printf("0\n");  
  15.         else printf("1\n");  
  16.     }  
  17.     return 0;  
  18. }  

我擦,为毛代码还是这么短惊恐,大神膜拜中。。。(过奖过奖生气,如有雷同,请相信这真的只是借鉴)

最后奉上尼姆(Nim)博弈,这种博弈其实就是分解成简单的博弈再一一求解

  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <algorithm>  
  4. #include <iostream>  
  5. using namespace std;  
  6. int a[200005],ans[200005][2];  
  7. int main()  
  8. {  
  9.     int n,i,j,cnt,s;  
  10.     while(~scanf("%d",&n),n)  
  11.     {  
  12.         cnt = 0;  
  13.         s = 0;  
  14.         for(i = 0; i<n; i++)  
  15.         {  
  16.             scanf("%d",&a[i]);  
  17.             s^=a[i];  
  18.         }  
  19.         for(i = 0; i<n; i++)  
  20.         {  
  21.             if(a[i] > (s^a[i]))  
  22.             {  
  23.                 ans[cnt][0] = a[i];  
  24.                 ans[cnt][1] = s^a[i];  
  25.                 cnt++;  
  26.             }  
  27.         }  
  28.        if(cnt)//判断先手是胜是负  
  29.         {  
  30.             printf("Yes\n");  
  31.             for(i = 0; i<cnt; i++)  
  32.                 printf("%d %d\n",ans[i][0],ans[i][1]);//输出若先手为胜的走法  
  33.         }  
  34.         else  
  35.             printf("No\n");  
  36.             cout<<cnt<<endl;//输出使先手为胜的方案的数目  
  37.     }  
  38.     return 0;  
  39. }  

这个稍微长一点,因为里面增加了很多步骤,大大方便了题目的求解。

从今天开始,你就可以骄(zhuang)傲(bi)的说:“今朝获此三模板,从此博弈是水题!”

博弈论具体只是详解 博弈论知识详解

展开阅读全文

没有更多推荐了,返回首页