【博弈论】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
posted on 2015-01-26 22:43 MMMoonLighttt 阅读(190) 评论(0) 编辑 收藏 举报