ZOJ3084_S-Nim

本文深入探讨了SG函数在解决石子游戏问题中的应用,通过求解石子堆的状态异或值,揭示了先手或后手的必胜策略。文章详细解释了SG函数的概念、由来及性质,并提供了使用动态规划实现求解的代码实例。

题目的意思是这样的,给定你若干堆石子,每次你可以从任一堆取出某些固定数量的石子,每次取完后必须保证没堆石子的数量不为0,谁无法操作了就算fail。

刚刚开始看题目的时候有点也没有思路,甚至连Sg函数也没有听过。后来学习了一番,说说自己的想法吧。

_________________有关SG函数的由来,性质及其我个人对sg函数的了解见下一篇日志。

这个题目可以这样考虑,由于每次可取的数字是一个给定的集合,我们可以求出所有的数所对应的sg的函数值(我用的是dp,不过好像跟多人喜欢用记忆化搜)。

由于博弈论里面的许多奇奇怪怪的定理,最终我们只要求出每一堆的石子数所对应的sg值的总共异或值ans,如果ans不等于0,那么说明先手有必胜的策略,否则后手有必胜的策略。

另外说明一下,sg函数值对应的是在当前状态能转化到的所有后继状态sg值中的第一个没有出现的非负整数。很神奇吧。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 10005
 5 using namespace std;
 6 
 7 bool vis[105];
 8 int a[105],sg[maxn],n,m,k,ans;
 9 
10 void getSG()
11 {
12     for (int i=0; i<maxn; i++)
13     {
14         memset(vis,false,sizeof vis);
15         for (int j=1; j<=n && a[j]<=i; j++) vis[sg[i-a[j]]]=true;
16         for (int j=0; ; j++)
17             if (!vis[j])
18             {
19                 sg[i]=j;
20                 break;
21             }
22     }
23 }
24 
25 int main()
26 {
27     while (scanf("%d",&n) && n)
28     {
29         for (int i=1; i<=n; i++) scanf("%d",&a[i]);
30         sort(a+1,a+1+n);
31         getSG();
32         scanf("%d",&m);
33         while (m--)
34         {
35             scanf("%d",&n);
36             ans=0;
37             while (n--) scanf("%d",&k),ans^=sg[k];
38             if (ans) printf("W");
39                 else printf("L");
40         }
41         printf("\n");
42     }
43 
44     return 0;
45 }

 

转载于:https://www.cnblogs.com/lochan/p/3372983.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值