博弈论

深碍√TFBOYSˉ_ 2022-04-12 05:57 378阅读 0赞

巴什博奕

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2149

有n个物品 ,有两个参与者A,B ,每人每次从中取[1,m]个 ,假设每人都取最优策略, 求谁最后取完物品 假设A先取

如果n=m+1,显然不管第一次A取多少个,都没办法取完,而剩下的物品B可以一次性取完,所以结果一定是B赢

因此,我们可以发现一个先取者的必胜策略,即对于n=(m+1)*k+s; 我们令A先取s个,那么对于B无论他取多少个,A都可以取一个数,使得A取的物品数+上次B取的物品数=m+1 这样就出现不管B取多少个,到最后总能剩下m+1 所以B一定会输;

  1. int n,m;
  2. int k=n%(m+1);
  3. if(k==0) cout<<"B Win"<<endl;
  4. else cout<<"A Win"<<endl;

斐波那契博弈

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2516

有n个物品 ,有两个参与者A,B ,每人每次从中取[1,上一个人取物品数的2倍]个 ,假设每人都取最优策略, 求谁最后取完物品 假设A先取

应用了斐波那契数列,“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和。

总结就是一句话:对于n 若是斐波那契数 则A赢; 否则B赢

sg函数参考链接:https://blog.csdn.net/yizhangbiao/article/details/51992022

一共有n个物品总结 sg[]==0 为必输策略

1 每次取1~m个 sg[x]=n%(m+1);

2 每次取任意个 sg[x]=x;

3每次取一系列不连续中数任意一个 mex(x);

威佐夫博奕(Wythoff Game)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1527

有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

关键在于判断 是不是 奇异局势

是 先手输 否 先手赢

判断条件 a==|b-a|*((sqrt(5)+1)/2)

那什么叫 奇异局势呢?

对于(ak,bk)(ak ≤ bk ,k=0,1,2,…,n) ak 是前面没有出现过的最小的自然数 ,bk=ak+k;

如:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)

性质1.任何自然数都包含在一个且仅有一个奇异局势中。 由于ak是未在前面出现过的最小自然数,所以有ak > ak-1 ,而 bk= ak + k > ak-1 + k-1 = bk-1 > ak-1 。所以性质1。成立。 2.任意操作都可将奇异局势变为非奇异局势。

尼姆博奕(Nimm Game)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1850

有m堆各若干个物品,两个人A,B轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

同威佐夫博弈一样 也是需要判断奇异局势 是 先手输 否 先手赢

判断条件

  1. int ans=0,a[1005];
  2. for(int i=1;i<=m;i++)
  3. {
  4. cin>>a[i];
  5. ans^=a[i];
  6. }
  7. if(ans==0) cout<<"B Win"<<endl;
  8. else cout<<"A Win"<<endl;

如何将非奇异局势变为 奇异局势 也就是说 A要赢 第一次应怎么取呢?

原理:m=3 时 对于(55,81,121),55(+)81=102,121-102=19,所以从121中拿走19个物品 就形成了奇异局势(55,81,102)

  1. else{
  2. int cnt=0;
  3. for(int i=1;i<=m;i++){
  4. int k=ans^a[i];
  5. if(k<a[i]) cnt++;
  6. }
  7. cout<<cnt<<endl;
  8. }

sg函数的应用

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

  1. #include<iostream>
  2. #include<cstring>
  3. using namespace std;
  4. int n,arr[15],sg[1005];
  5. int mex(int x){
  6. if(sg[x]!=-1) return sg[x]; //如果sg[x]不为-1 直接输出
  7. bool vis[1005];
  8. for(int i=0;i<1005;i++)
  9. vis[i]=false;//初始化标志位
  10. for(int i=0;i<=10;i++) {
  11. int temp=x-arr[i];
  12. if(temp<0) break;
  13. sg[temp]=mex(temp);//相当于dfs
  14. vis[sg[temp]]=true;//该值出现过 标记
  15. }
  16. for(int i=0;;i++){
  17. if(!vis[i]) {
  18. sg[x]=i;break;//当前sg[]集合中未出现的最小的自然数
  19. }
  20. }
  21. return sg[x];
  22. }
  23. int main(){
  24. arr[0]=1;
  25. for(int i=1;i<=10;i++)
  26. arr[i]=arr[i-1]*2;//数组arr[]初始化 即每步可选择的牌数
  27. while(cin>>n){
  28. memset(sg,-1,sizeof(sg));//初始化 因为sg函数要求的是大于等于0 所以初始化为-1
  29. if(mex(n)) cout<<"Kiki"<<endl;//mex 函数是关键
  30. else cout<<"Cici"<<endl;
  31. }
  32. return 0;
  33. }

组合博弈

有n堆石子,每次可以从第1堆石子里取1颗、2颗或3颗,可以从第2堆石子里取奇数颗,可以从第3堆及以后石子里取任意颗……

我们可以把它看作3个子游戏,第1个子游戏只有一堆石子,每次可以取1、2、3颗,很容易看出x颗石子的局面的SG值是x%4。 第2个子游戏也是只有一堆 石子,每次可以取奇数颗,经过简单的画图可以知道这个游戏有x颗石子时的SG值是x%2。 第3个游戏有n-2堆石子,就是一个Nim游戏。对于原游戏的每 个局面,把三个子游戏的SG值异或一下就得到了整个游戏的SG值,然后就可以根据这个SG值判断是否有必胜策略以及做出决策了。其实看作3个子游戏还是保 守了些,干脆看作n个子游戏,其中第1、2个子游戏如上所述,第3个及以后的子游戏都是“1堆石子,每次取几颗都可以”,称为“任取石子游戏”,这个超简单的游戏有x颗石子的SG值显然就是x。 最后的sg值显然就是三个sg值的异或和

发表评论

表情:
评论列表 (有 0 条评论,378人围观)

还没有评论,来说两句吧...

相关阅读

    相关 初识--博弈论

    > 今天听见宋老师说多看经济学能提高智商,推荐了“博弈论”然后随手b站搜出耶鲁大学公开课,点开一看“133.1万播放,近30w的收藏”,周末早上8点半同时在线观看32个人,上课

    相关 取石子-博弈论

    有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可。两个人轮流从堆中取物 体若干,规定最后取光物体者取胜。这是我国民间很古老的一个游戏,别看这游戏极其简单

    相关 博弈论

    博弈论 看了两天博弈,做了一点题,写一写,把自己学会的东西记录下来。 巴什博奕(Bash Game) 只有一堆n个物品,两个人轮流从这

    相关 博弈论模板

    一。巴什博弈 只是最简单的博弈了,只简单说一下满足条件,一堆总数为n个,每次可以取1-m个石头。 核心是n=(m+1)\r+s;也就是说用n%(m+1) 判断是否等于0即可。

    相关 博弈论

    博弈论 巴什博弈 尼姆博弈 威佐夫博弈 巴什博弈 问题类型: 只有一堆n个物品,两个人从轮流中取出(1~m)个,最后取光者得胜; bo

    相关 博弈论问题

    \\ 博弈论问题——双人取棋子 \\ 1.问题描述 一共有19枚棋子,两人轮流取,每人每次可以取1枚或2枚或3枚,己方先取,拿到最后一枚棋子算输,问何种取法可以