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 }

 

posted @ 2017-01-19 23:05  mzl0707  阅读(272)  评论(0编辑  收藏  举报