Nim游戏

Nim游戏

题目描述

甲,乙两个人玩\(Nim\)取石子游戏。

\(Nim\)游戏的规则是这样的:地上有\(n\)堆石子\((\)每堆石子数量小于\(10000)\),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这\(n\)堆石子的数量,他想知道是否存在先手必胜的策略。

输入输出格式

输入格式:

第一行一个整数\(T \leq 10\),表示有T组数据

接下来每两行是一组数据,第一行一个整数\(n\),表示有\(n\)堆石子,\(n \leq10000\);

第二行有\(n\)个数,表示每一堆石子的数量

输出格式:

\(T\)行,如果对于这组数据存在先手必胜策略则输出 Yes ,否则输出No,不包含引号,每个单词一行。




今天刚学会的一点博弈论的基础,趁热打铁,赶紧巩固.

博弈论\(DP\)

\(Nim\)游戏的特征:

  1. 两人游戏
  2. 回合制游戏
  3. 某一方无法操作时为败

\(1\)

现在有一个游戏 \(G1\) , 有两个人 \(Alice,Bob\) 玩游戏,\(Alice\)先手,两人轮流 取石子,每次可以取走任意数量的石子 , 当某个时刻某人无法取石子时此人输,则\(Alice\)是必胜还是必败?

很容易可以看出\(Alice\)只要取走所有的石子,那么\(Bob\)必败,因此\(Alice\)必胜.下面用\(DP\)的方法解决这个问题.

  • \(f[i]\) 代表还剩 \(i\) 个时石头对当前先手是必胜还是必败
    • 必胜 : \(f[i]=1\)
    • 必败 : \(f[i]=0\)
  • \(f[0]=0\),以为无石子可取
    • \(f[i]\) 可以转移到 \(f[i-1],f[i-2],f[i-3],...\)
    • 如果 \(f[i]\) 能够转移到的所有状态中有\(1\)个必败态\(,f[i]\)为必胜态
    • 如果 \(f[i]\) 能转移到的所有状态中全是必胜态\(,f[i]\)为必败态

之所以会有以上两句结论,是因为\(f[i]\)定义中的"先手"并不是固定的,如现在\(f[1]\)的先手是\(Alice\),则转以后的"先手"就成了\(Bob\),因此此处的"先手"应该是"当前的操作者".

现在有一个游戏\(G2\),有\(N\)个石子,每次可以拿走\(3,4\)\(5\)个石子.\(Alice\)先手.问\(Alice\)必胜还是必败

  • \(f[i]\)为还剩\(i\)个石子时先手必胜还是必败.
    • \(f[i]\) 可以转移到\(f[i-3],f[i-4],f[i-5]\)
    • 如果\(f[i-3],f[i-4],f[i-5]\)中有一个为必败态,则\(f[i]\)为必胜态
    • 如果\(f[i-3],f[i-4],f[i-5]\)全为必胜态,则\(f[i]\)为必败态

打表找规律:当 \(i\ MOD \ 8=0,1,2\) 时必胜,否则必败.


\(2\)

两堆石头, \(N_1,N_2\) , 每次从其中某一堆取走任意多的石子,先手必胜/必败 \(?\)

  • \(f[i][j]\) 表示两堆石子分别有\(i,j\)个时先手必胜还是必败.
  • $ f[i][j]\rightarrow f[x][j]/f[i][y]\ \ ,\ \ $

\(3\)

现在有一个游戏\(G\)\(k\)个小游戏组成. $ G=(g_1,g_2.g_3,...,g_k)\ ,\ $第 \(i\) 个游戏是有$ N_i$ 堆石子的取石子游戏.
\(Alice\)\(Bob\)进行石子游戏,一共有\(k\)堆石子,第\(i\)堆石子有\(N_i\)个石子.\(Alice\)先手,轮流取石子,每次可以从某一堆石子中取出任意多的石子.问\(Alice\)必胜还是必败

解决这个问题需要引入一个数学概念:

\(SG\) 函数. \(sg[i]\) 为当石头还剩 \(i\) 个的时候的 \(SG\)

  • 对于一个必败态,其SG值为\(0 \Longrightarrow sg[0]=0\) , 若\(SG\)值不为\(0\),则为必胜态.
  • \(sg[i]=\ mex \{sg[i-1],sg[i-2],sg[i-3],...,sg[0]\}\)
    • \(mex\ \ S\) : 返回最小的一个自然数\(n\),使\(n\not \in \ S\)
    • \(\Longrightarrow \ sg[i]=i\)\(\ \ \ \ \ (*)\)

\(SG\) 定理 \(\ \ SG[G]=sg[g_1]\ \ XOR\ \ sg[g_2]\ \ XOR\ \ sg[g_3]\ \ XOR...XOR\ \ sg[g_k]\)
\(SG\)定理和上面的结论\((*)\)可知 \(:\ \ SG[G]=n_1\ \ XOR\ n_2\ XOR\ n_3\ XOR\ ...\ XOR\ \ n_k\)

因此,此题的答案即为各堆石子的个数的异或


#include <cstdio>
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,sg,ans=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&sg);
			ans ^= sg;
		}
		if(ans) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}
posted @ 2018-10-05 20:57  昤昽  阅读(161)  评论(0编辑  收藏  举报