例题:Nim游戏
给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 n。
第二行包含 n 个数字,其中第 i 个数字表示第 i 堆石子的数量。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n≤
1
0
5
10^5
105,
1≤每堆石子数≤
1
0
9
10^9
109
输入样例:
2
2 3
输出样例:
Yes
答案:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String[] str = bufferedReader.readLine().split(" ");
int n = Integer.parseInt(str[0]);
int[] a = new int[n];
str = bufferedReader.readLine().split(" ");
for (int i = 0; i < n; i++) {
a[i] = Integer.parseInt(str[i]);
}
int t = a[0];
for (int i = 1; i < n; i++) {
t = t ^ a[i];
}
if (t == 0)
System.out.println("No");
else
System.out.println("Yes");
}
}
例题2:台阶-Nim游戏
现在,有一个 n 级台阶的楼梯,每级台阶上都有若干个石子,其中第 i 级台阶上有 ai 个石子(i≥1)。
两位玩家轮流操作,每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中(不能不拿)。
已经拿到地面上的石子不能再拿,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 n。
第二行包含 n 个整数,其中第 i 个整数表示第 i 级台阶上的石子数 ai。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n≤
1
0
5
10^5
105,
1≤ai≤
1
0
9
10^9
109
输入样例:
3
2 1 3
输出样例:
Yes
答案:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String[] str = bufferedReader.readLine().split(" ");
int n = Integer.parseInt(str[0]);
int[] a = new int[n];
str = bufferedReader.readLine().split(" ");
for (int i = 0; i < n; i++) {
a[i] = Integer.parseInt(str[i]);
}
int t = a[0];
for (int i = 1; i < n; i++) {
if (i % 2 == 0)
t = t ^ a[i];
}
if (t == 0)
System.out.println("No");
else
System.out.println("Yes");
}
}
例题3:集合-Nim游戏
给定 n 堆石子以及一个由 k 个不同正整数构成的数字集合 S。
现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合 S,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 k,表示数字集合 S 中数字的个数。
第二行包含 k 个整数,其中第 i个整数表示数字集合 S 中的第 i 个数 si。
第三行包含整数 nn。
第四行包含 n 个整数,其中第 i 个整数表示第 i堆石子的数量 hi。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n,k≤100,
1≤si,hi≤10000
输入样例:
2
2 5
3
2 4 7
输出样例:
Yes
答案:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static int[] a, s, f;
static int k;
public static int sg(int x) {
if (f[x] != -1) return f[x];
Set<Integer> set = new HashSet<>();
for (int i = 0; i < k; i++) {
int sum = s[i];
if (x >= sum) set.add(sg(x - sum));
}
for (int i = 0; ; i++)
if (!set.contains(i))
return f[x] = i;
}
public static void main(String[] args) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String[] str = bufferedReader.readLine().split(" ");
k = Integer.parseInt(str[0]);
s = new int[k];
f = new int[10010];
Arrays.fill(f, -1);
str = bufferedReader.readLine().split(" ");
for (int i = 0; i < k; i++) {
s[i] = Integer.parseInt(str[i]);
}
str = bufferedReader.readLine().split(" ");
int n = Integer.parseInt(str[0]);
a = new int[n];
str = bufferedReader.readLine().split(" ");
int res = 0;
for (int i = 0; i < n; i++) {
a[i] = Integer.parseInt(str[i]);
res = res ^ sg(a[i]);
}
if (res == 0) System.out.println("No");
else System.out.println("Yes");
}
}