蓝桥杯2012年 取球游戏(博弈论三种解法)
题目:
题目描述
今盒子里有 n 个小球,A、B 两人轮流从盒中取球,每个人都可以看到另一>个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会>做出错误的判断。
我们约定:
每个人从盒子中取出的球的数目必须是:1,3,7 或者 8 个。轮到某一方取>球时不能弃权!A 先取球,然后双方交替取球,直到取完。被迫拿到最后一>个球的一方为负方(输方)
请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A 是否>能赢?
输入描述
先是一个整数 n (n<100),表示接下来有 n 个整数。
然后是 n 个整数,每个占一行(整数< 10^4),表示初始球数。
输出描述
程序则输出 n 行,表示 A 的输赢情况(输为 0,赢为 1)。
输入输出样例
示例
输入
4
1
2
10
18
输出
0
1
1
0
运行限制
最大运行时间:1s
最大运行内存: 256M
解法一:sg函数解法
代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N = 10005;
static int[] sg = new int[N];
static int[] arr = {1, 3, 7, 8};
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
while (n-- > 0) {
Arrays.fill(sg, -1);
int x = scan.nextInt();
System.out.println(getSg(x - 1) == 0 ? 0 : 1); // 对手拿完了n-1个球,留下最后一个球,自己为必败状态
}
}
public static int getSg(int x) {
if (sg[x] != -1) return sg[x];
boolean[] vis = new boolean[N];
for (int i = 0; i < 4 && x >= arr[i]; i++) {
vis[sg[x - arr[i]] = getSg(x - arr[i])] = true;
}
for (int i = 0; ; i++) if (!vis[i]) return sg[x] = i;
}
}
解法二:dfs+记忆化
代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N = 10005;
static int[] arr = {1, 3, 7, 8};
static int[] dp = new int[N];
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
while (n-- > 0) {
Arrays.fill(dp, -1);
int x = scan.nextInt();
System.out.println(dfs(x));
}
}
public static int dfs(int x) {
if (dp[x] != -1) return dp[x];
if (x <= 1) return dp[x] = 1 - x; // 为1必败,为0必胜
for (int i = 0; i < 4 && x >= arr[i]; i++) {
if (dfs(x - arr[i]) == 0) return dp[x] = 1;
}
return dp[x] = 0;
}
}
解法三:动态规划(正推)
代码:
import java.util.Scanner;
public class Main {
static int N = 10010;
static int[] dp = new int[N];
static {
for (int i = 1; i < 10001; i++)
if (dp[i] == 0) // 当此时为必败状态,下面四种情况则是必胜状态
dp[i + 1] = dp[i + 3] = dp[i + 7] = dp[i + 8] = 1;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
while (n-- > 0) {
System.out.println(dp[scan.nextInt()]);
}
}
}