(一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规
定每次至少取一个,最多取m个。最后取光者得胜。

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

这种情况下是颇为复杂的。我们用(ak,bk)(ak ≤ bk ,k=0,1,2,…,n)表示
两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们
称为奇异局势。前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,
10)、(8,13)、(9,15)、(11,18)、(12,20)。

可以看出,a0=b0=0,ak是未在前面出现过的最小自然数,而 bk= ak + k,奇异局势有
如下三条性质:

1。任何自然数都包含在一个且仅有一个奇异局势中。
    由于ak是未在前面出现过的最小自然数,所以有ak > ak-1 ,而 bk= ak + k > ak
-1 + k-1 = bk-1 > ak-1 。所以性质1。成立。
    2。任意操作都可将奇异局势变为非奇异局势。
    事实上,若只改变奇异局势(ak,bk)的某一个分量,那么另一个分量不可能在其
他奇异局势中,所以必然是非奇异局势。如果使(ak,bk)的两个分量同时减少,则由
于其差不变,且不可能是其他奇异局势的差,因此也是非奇异局势。
    3。采用适当的方法,可以将非奇异局势变为奇异局势。

假设面对的局势是(a,b),若 b = a,则同时从两堆中取走 a 个物体,就变为了
奇异局势(0,0);如果a = ak ,b > bk,那么,取走b  – bk个物体,即变为奇异局
势;如果 a = ak ,  b < bk ,则同时从两堆中拿走 ak – ab + ak个物体,变为奇异局
势( ab – ak , ab – ak+ b – ak);如果a > ak ,b= ak + k,则从第一堆中拿走多余
的数量a – ak 即可;如果a < ak ,b= ak + k,分两种情况,第一种,a=aj (j < k)
,从第二堆里面拿走 b – bj 即可;第二种,a=bj (j < k),从第二堆里面拿走 b – a
j 即可。

从如上性质可知,两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜
;反之,则后拿者取胜。

那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式:

ak =[k(1+√5)/2],bk= ak + k  (k=0,1,2,…,n 方括号表示取整函数)

奇妙的是其中出现了黄金分割数(1+√5)/2 = 1。618…,因此,由ak,bk组成的矩形近
似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],若a=[
j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a = aj+1,bj+1 = aj+1
+ j + 1,若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异
局势。

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

对于一个尼姆博弈的局面(a1,a2,...,an),它是P-position当且仅当ans=a1^a2^...^an=0,其中^表示异或(xor)运算。
对于任何一个非奇异局势都可以通过取若干取某一堆的若干个石子让它变成奇异局势,具体计算方法为,将之前计算的得到
的ans(>0)与A[i]异或,如果满足ans^A[i]<A[i](因为石子只能减少不能增加),则在该堆中取A[i]-ans^A[i]就可以让非奇异局势变为奇异局势。
更多博弈论知识见http://www.cnblogs.com/kuangbin/archive/2011/08/28/2156426.html
巴什博弈(一堆,每次取得数量有限)
1.hdu1846 巴什博弈裸题
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int main()
{int T;cin>>T;int n,m;while(T--){scanf("%d%d",&n,&m);if(n%(m+1)==0)printf("second\n");else printf("first\n");}
}

2.hdu1847 简单分析就可以发现若当前局势是三的倍数,那就是一个奇异形势,先手必输,若不是先手可以
取走相应石子使其变成三的倍数,则先手获胜。
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int main()
{int n;while(~scanf("%d",&n)){if(n%3==0)printf("Cici\n");else printf("Kiki\n");}
}

威佐夫博弈(两堆石子,一堆取任意多或者两堆取一样多)
1.hdu1527 威佐夫博弈裸题
/*hdu1527
简单威佐夫博弈
只需要判断是否满足奇异局势条件即可
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
int main()
{int a,b;while(~scanf("%d%d",&a,&b)){if(a>b) swap(a,b);int k=b-a;//第k+1个奇异局势//cout<<k<<endl;int p=(int)((k*(1+sqrt(5.0)))/2);//cout<<p<<endl;printf("%d\n",(a==p)?0:1);}
}

2.hdu2177 与上一道题唯一不同在于如果先手赢,输出他取一次后的情况。判断还是直接判断
若当前局势不是奇异局势,让他变成奇异局势有两种情况,一种是整体减,另一种是减一个
整体减因为差值k不变,便可以计算出ak,如果a>ak输出(ak,ak+k)即可,另外一种情况
暴力枚举即可,具体变哪一堆又是两种情况,注意a==b的情况,只判断一种就可以。
/*hdu15
简单威佐夫博弈
只需要判断是否满足奇异局势条件即可
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
int main()
{int a,b;double g=(1+sqrt(5.0))/2;while(~scanf("%d%d",&a,&b)&&(a||b)){int k=b-a;//第k+1个奇异局势int p=(int)(k*g);if(a==p) {printf("0\n");continue;}printf("1\n");if(a>p){printf("%d %d\n",p,p+k);}for(int i=a-1;i>=0;i--){int x=i,y=b;int l=b-i;if((int)(g*l)==x){printf("%d %d\n",x,y);}}for(int i=b-1;i>=0;i--){if(a==b) break;int x=a,y=i;if(x>y) swap(x,y);int l=y-x;if((int)(g*l)==x){printf("%d %d\n",x,y);}}}
}

尼姆博弈:
1.hdu1849 只需要一步转化即可,每个石子的位置相当于该堆石子的个数,然后这道题就变成了尼姆
博弈的裸题,直接套公式判断即可,ans初始化为0即可,因为0异或任何数都是它本身。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{int n;while(scanf("%d",&n),n){int a;int ans=0;while(n--){scanf("%d",&a);ans^=a;}if(ans) cout<<"Rabbit Win!"<<endl;//非奇异局势else cout<<"Grass Win!"<<endl;}return 0;
}

2.hdu2176 依然是一道尼姆博弈的裸题
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=200000+100;
int pile[maxn];
int main()
{int m;while(scanf("%d",&m)&&m){int ans=0;for(int i=1;i<=m;i++){scanf("%d",&pile[i]);ans^=pile[i];}if(ans==0){printf("No\n");continue;}printf("Yes\n");for(int i=1;i<=m;i++){if(pile[i]>(ans^pile[i])){printf("%d %d\n",pile[i],pile[i]^ans);}}}
}

hdu1564 考奇偶性变化(有几分对称构造的意味)

S表示起点。如果n为偶数,那么所有格子可以被2*1的砖块覆盖掉。这样先手每次都移动到当前1*2的另外一块。、

先手必赢。 如果n为奇数。出了起始那个店,其余点都可以被覆盖。所有后手赢

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{int n;while(~scanf("%d",&n)&&n){if(n&1)printf("ailyanlu\n");else  printf("8600\n");}
}

hdu3951 对称构造,如果是一个或两个硬币,先手必胜,如果n>=3先手取了以原本的环就变成了一条链,后手可以根据

剩余的硬币的数目选择取一个或两个把一条链变成两条相同的链,先手不论在其中一条链进行什么操作,后手只需要在另一条
链做相同操作就可以,后手必胜。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{int n;while(~scanf("%d",&n)&&n){if(n>=3) cout<<"Bob"<<endl;else cout<<"Alice"<<endl;}
}

poj1740 [转]

*题目大意:

* 对于n堆石子,每堆若干个,两人轮流操作,每次操作分两步,

* 第一步从某堆中去掉至少一个,第二步(可省略)把该堆剩余

* 石子的一部分分给其它的某些堆。最后谁无子可取即输。

*解题思路:

* 1、先考虑1堆的时候,1堆当然是N点(必胜点),

* 2、然后考虑2堆,细想一下可以发现,当2堆一样时,这个时候

* 的目的就是要把对方给逼到只有2堆都是1的时候,就能必胜了。

* 但是想一下,后手只要模范先手所做的动作,那么最后就会形成

* 两堆都是1的局势,所以当2堆相同时,是一个P点(必败点)。

* 注意当2堆不一样的时候,先手可以把它变成一样,此时变为N点。

* 3、考虑3堆,这个时候,先手必定是可以把局势变成2堆相同的堆的,

* 那么先手肯定胜利,为N点。** (发现,当堆为偶数堆两两同高的时候,此时是P点)

** 偶数:

* 4、当n >= 4堆的时候可以发现,可以把堆的高度按从小到大排列。

* 当n为偶数的时候,可以把最高的那一堆跟最小的那一堆变成一样,

* 然后把高度差用来平衡剩余的那些堆,注意一定是可以平衡的,

* 因为把剩余的堆相邻两两的差值投射到y轴上发现这些离散的线段和

* 小于最高堆于最小堆的差值。* 奇数:

* 5、当n >= 4堆的时候可以发现,可以把堆的高度按从小到大排列。

* 当n为奇数的时候,可以把最高堆给去掉,然后分配给其它堆,

* 注意前面的相邻堆两两的差值投射到y轴,最后的总和还是小于* 最高堆的。

总之,奇数堆是必胜点,偶数堆要判断是否两堆两两相等(必败态),否则必胜态。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100;
int a[maxn];
int main()
{int n;while(~scanf("%d",&n)&&n){for(int i=1;i<=n;i++)scanf("%d",&a[i]);int ans=0;int flag=1;if(n%2==1){cout<<1<<endl;flag=0;}else{sort(a+1,a+n+1);for(int i=1;i<=n;i+=2){if(a[i]!=a[i+1]){cout<<1<<endl;flag=0;break;}}}if(flag) cout<<0<<endl;}
}

hdu1538 海盗分金,推理博弈:这道题的情况算是比较复杂的需要考虑全面
http://www.cnblogs.com/clliff/p/4260697.html这个博客解析写的不错,可以去看看
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100;
int a[maxn];
int fac[15]={2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
void solve(int n,int m,int p)
{if(n<=2*m)//金币数足够贿赂
    {if(n==p){printf("%d\n",m-(n-1)/2);return;}else if((p&1)==(n&1)){printf("1\n");return;}else{printf("0\n");return;}}if(n==2*m+1){if(p==n){printf("0\n");return;}else if(p&1)//保命优先
        {printf("1\n");return;}else{printf("0\n");return;}}int t=n-2*m;//不够贿赂for(int i=0;i<15;i++){if(t==fac[i]){printf("0\n");return;}}for(int i=1;i<=14;i++){if(t<fac[i]){if(p>2*m+fac[i-1]&&p<2*m+fac[i])printf("Thrown\n");elseprintf("0\n");return ;}}
}
int main()
{int n,m,p;int T;scanf("%d",&T);while(T--){scanf("%d%d%d",&n,&m,&p);solve(n,m,p);}
}

转载于:https://www.cnblogs.com/xuejianye/p/5679814.html

简单博弈论总结加例题解析相关推荐

  1. Universal-Image-Loader解析(二)——DisplayImageOptions的详细配置与简单的图片加载...

    在使用这个框架的时候,我们必须要配置一个DisplayImageOptions对象来作为ImageLoader.getInstance().displayImage()中的参数,所以很有必要讲解这个对 ...

  2. 转载:BP(反向传播算法)公式推导及例题解析

    首发于 深度学习与我的那些事 写文章 BP(反向传播算法)公式推导及例题解析 WILL 深度学习搬砖者 ​ 关注他 297 人 赞同了该文章 写在前面:最近赶上<模式识别>课程考试,就把B ...

  3. c语言入门中冒泡排序的例题,选择排序和冒泡排序例题解析(c语言)

    排序算法排序算法 1.简单选择排序简单选择排序 假设有 n 个数,作简单选择排序简单选择排序,按升序排列: 先通过 n-1 次比较,从 n 个值中找出最小值,将它与第一个值交换. 再通过 n-2 次比 ...

  4. 简单的网络图片加载工具类

    简单的网络图片加载工具类 根据图片url网址解生成图片,首先解析图片的流信息,然后通过bitmapfactory工具类生成bitmap图片,设置到图片控件上即可,详情看代码 import androi ...

  5. script标签的加载解析执行

    看了很多网上的文章,都是大同小异.总结一下.内部原理还没有搞清楚,有机会再学习. 一.<script>标签的加载解析执行顺序 html页面中的<script>标签中的内容(直接 ...

  6. Oracle:经典例题解析

    1.环境准备 下面所有SQL语句都是建立在employees表和departments表上,具体表结构如下所示: departments表结构如下所示: 字段名 数据类型 长度 约束 说明 depar ...

  7. 计算机电子技术叠加原理,叠加定理适用于什么电路?电路叠加原理例题解析

    叠加定理适用于什么电路?电路叠加原理例题解析 叠加定理是否适用于二极管电路 叠加原理是针对线性电路的,二极管是非线性的. 叠加定理陈述为:由全部独立电源在线性电阻电路中产生的任一电压或电流,等于每一个 ...

  8. 【C语言】自定义函数例题解析

    C语言函数例题解析 C语言函数解析 C语言函数例题解析 值传递 自定义函数求解一元二次方程 自定义函数计算给定日期是该年的第几天 地址传递 自定义函数对N个数排序 自定义函数对字符串的处理 值传递 自 ...

  9. [算法系列] 深入递归本质+经典例题解析——如何逐步生成, 以此类推,步步为营

    [算法系列] 深入递归本质+经典例题解析--如何逐步生成, 以此类推,步步为营 本文是递归系列的第三篇, 第一篇介绍了递归的形式以及递归设计方法(迭代改递归),;第二篇以递归为引子, 详细介绍了快排和 ...

最新文章

  1. 计算机二级第十九套题电子表格,2012年计算机二级Access第十九套上机试题及答案详解...
  2. EF Core 实现多租户
  3. 为什么用链路聚合_H3C ComwareV7平台网络设备可靠性配置——链路聚合
  4. PHP操作Redis常用技巧
  5. js urlencode 20 php,js实现php函数urlencode
  6. CKEditor的使用-编辑文本
  7. C++之一个函数链的简单例子(分文件实现)
  8. java 多态 重载的区别_重写、覆盖、重载、多态几个概念的区别分析
  9. 芝麻开门-如何解决电脑PIN码忘记了不能登录问题
  10. 2019 Multi-University Training Contest 2:Beauty Of Unimodal Sequence(DP + 贪心构造)
  11. 如何使用腾讯云GPU云服务器完成 blender 的动画图片渲染
  12. php汉字转换拼音的类 做了修改用mb_convert_encoding代替iconv实现编码转换
  13. python半圆_如何在Python中使用Zelle图形制作半圆?
  14. OpenCV————鼠标绘制和滑动条
  15. Python 3.10版本及其依赖项 Linux下源码编译 安装到指定路径/目录
  16. 清云小程序教程十六:主轴与交叉轴二
  17. 国之殤! 哀悼汶川大地震! 表达我的哀思!
  18. C# System.ObjectDisposedException:“无法访问已释放的对象。 ObjectDisposed_ObjectName_Name”
  19. 镁客网每周硬科技领域投融资汇总(1.20-1.26),微软出手再收购开源服务商...
  20. 第一类修正贝塞尔函数

热门文章

  1. 字符设备驱动笔记(二)
  2. SVN 服务器的安装和配置(Gentoo)
  3. 去除html标签的工具类,Java正则匹配过滤移除html标签以及获取img完整标签工具类...
  4. java并发编程之线程的生命周期详解
  5. linux 使用碎碎记
  6. 数据结构之 栈与队列(一)
  7. oracle数据库匿名快,pl/sql分匿名块和命名块
  8. 怎么把php网站变灰,CSS效果,让网站全部变成灰色(黑白)
  9. 两个网口芯片接一个变压器_一看就会:详细讲解网络变压器作用
  10. android retrofit 2.0公共参数,Retrofit2.0 添加公共参数