bzoj1874: [BeiJing2009 WinterCamp]取石子游戏(博弈论+SG函数入门)
昨天在唐神的引导下看了有关博弈论的知识,总算是有点了解,觉得这东西比较抽象,但是很神奇很有趣。
一个nim游戏中,每堆石子的sg函数其实可以理解为此状态到不了的状态,我觉得从某种意义上来讲就可以代表此状态
判断一个游戏局面先手是否必胜,求所有点的sg值得亦或和sum
sum为0必败,其他必胜。原理可以百度“博弈论 sg函数”有详解
同时如果有若干个子游戏,则sum为若干个子游戏的亦或和
虽然看是看懂了,但是实际运用起来并不怎么通透。。
此题为入门题,预处理出sg值
sg值可以由所能到达的各状态的sg值推得
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 15; 6 int n,a[maxn],ans,sg[1001],f[maxn],m,hash[1001]; 7 8 void get_sg(){ 9 sg[0]=0; 10 for (int i=1; i<=1000; i++){ 11 for (int j=1; j<=m && i-f[j]>=0; j++) 12 hash[sg[i-f[j]]]=i; 13 for (int j=0; j<=i+1; j++) 14 if (hash[j]!=i){sg[i]=j;break;} 15 } 16 } 17 18 int main(){ 19 scanf("%d", &n); 20 for (int i=1; i<=n; i++) scanf("%d", &a[i]); 21 scanf("%d", &m); 22 for (int i=1; i<=m; i++) scanf("%d", &f[i]); 23 get_sg(); 24 for (int i=1; i<=n; i++) ans^=sg[a[i]]; 25 if (!ans){puts("NO");return 0;} 26 for (int i=1; i<=n; i++){ 27 int tmp=ans^sg[a[i]]; 28 for (int j=1; j<=m && a[i]>=f[j]; j++) 29 if (!(tmp^sg[a[i]-f[j]])){ 30 puts("YES"); 31 printf("%d %d\n", i, f[j]); 32 return 0; 33 } 34 } 35 return 0; 36 }