标签:lse set count tin 如何 注意 div 威佐夫博奕 ref
一直害怕博弈论的题目,觉得最优不最优什么的都好扯淡啊。。。
现在终于鼓起勇气学习一下。
一、巴什博奕)
描述:有两个人 面对 一堆 物品,总共n个,每次每个人最少取一个,最多取m个,最后取完者获胜。
分析:显然,如果有小于m个,那先取者获胜;如果有m+1个,后取者总能获胜。所以某玩家只要当前形势是m+1个,或者m+1个的倍数,那么他最后肯定能获胜的啦~~
即,n = (m+1)*r + s,那么取s个就好啦~~~
变种:报数,每个人当前最多报m‘个数,最少报1个数,谁先报数100个谁赢。
二、威佐夫博奕(Wythoff Game)
描述:有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜
暂时没遇到这样的题目。。。
三、尼姆博弈
一共有n堆,两个人每次从一堆取出石头,最后取出者赢;
变形:最后取出者输。
解决办法:
奇异态先手输,否则先手赢;单数如果变形,要判断奇偶,再按照这条规则。
描述:有三堆或者多堆若干多物品,两个人每次轮流选,每次最多不限,最少选1个,取完者获胜。。。
推荐HDOJ题目
http://acm.hdu.edu.cn/showproblem.php?pid=1907
http://acm.hdu.edu.cn/showproblem.php?pid=2509
都是变形的尼姆博弈
分析:我们用(a,b,c)表示某种局势,首先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局势是(0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0)。仔细分析一下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n,n)的情形。那么我们只要将当前局势变为奇异局势即可(任何奇异局势(a,b,c)都有a(+)b(+)c =0。)
如果我们面对的是一个非奇异局势(a,b,c),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c 变为 a(+)b,即可,因为有如下的运算结果: a(+)b(+)(a(+)b)=(a(+)a)(+)(b(+)b)=0(+)0=0。要将c 变为a(+)b,只要从 c中减去 c-(a(+)b)即可。
注意,当最后一个取完的是赢者的时候,那么当前奇异态是先手必赢的状态,
当最后一个取完的是输者的时候,先判断是否都是非充裕堆(为1),全为1判断奇偶,在判断当前是否是奇异态。
例如 hdu1907,最后取完的是输者。虽然不知道为什么要判断奇偶真的不知道。。。。。。。。。。。。。。。。。。。。。。
好吧好吧,接下来就是sg函数了
上模板
int mex(set<int>&s){ int a = 0; if(s.count(a)) a++; return a; } while(scanf("%d",&n) != EOF){ int sg[1010] = {0}; for(int i = 1;i <= n;i++){ set<int>s; for(int j = 0;j < numd;j++){ if(i - d[j] < 0) continue; s.insert(sg[i-d[j]]); } sg[i] = mex(s); } if(sg[n] == 0){ cout << "后手" << endl; } else cout <<"先手" << endl; }
标签:lse set count tin 如何 注意 div 威佐夫博奕 ref
原文地址:https://www.cnblogs.com/xuyanqd/p/8947308.html