首页 > 代码库 > 【博弈论】BZOJ 1115-石子游戏
【博弈论】BZOJ 1115-石子游戏
题意:有N堆石子,除了第一堆外,每堆石子个数都不少于前一堆的石子个数。两人轮流操作 每次操作可以从一堆石子中移走任意多石子,但是要保证操作后仍然满足初始时的条件 谁没有石子可移时输掉游戏。问先手是否必胜。
这个题是一个阶梯博弈的问题。一开始没有接触过,各种度娘然后搞懂了,赶快记下来。
何为阶梯博弈?
简单的用Nim来说,一段台阶上,每个台阶上放了一堆石子,每次能从除了第一阶的台阶上取任意多石子向下放一级。无法操作的人输。
神犇告诉我,这个游戏的SG值就是奇数阶梯的SG值Xor起来...跪拜。
那么来证明一下。
如果只考虑奇数阶的情况我是必胜态,那么在这个游戏存在一个策略使我必胜——
按只考虑奇数阶的策略行动。那么对手现在处于必败态。如果对手移动的是奇数阶的,依旧按照奇数阶的必胜策略行动。
而如果对手移动的是偶数阶的,我可以将对手移动的石子再移动到下一阶。石子的数量和堆数都是之前我的状态,即对手的必败态。
如此重复,偶数阶的最后一颗石子一定是我将某些数量的石子由2->1。
可以看到,偶数阶对答案和决策并没有影响。
以上就是神奇的阶梯博弈!
那么这个题目需要稍微转换一下。
第i堆移走x个石子后,第i+1堆多了x个石子可以操作。是不是相当于将x个石子移动到了下一阶?
剩下的自己YY一下吧,贴个代码。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 7 int ans,a[10005],n,i,T; 8 9 int main()10 {11 scanf("%d",&T);12 while (T--)13 {14 scanf("%d\n",&n); ans = 0;15 for (i = 1; i <= n; i++) scanf("%d",&a[i]);16 17 for (i = n; i > 1; i -= 2) ans ^= (a[i]-a[i-1]);18 if (n % 2) ans ^= a[1];19 20 if (ans) printf("TAK\n"); else printf("NIE\n");21 }22 23 return 0;24 }25
【博弈论】BZOJ 1115-石子游戏
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。