“取球游戏” 三种题解方式
题目描述:
今盒子里有n个小球,A、B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断。
我们约定:
每个人从盒子中取出的球的数目必须是:1,3,7或者8个。
轮到某一方取球时不能弃权!
A先取球,然后双方交替取球,直到取完。
被迫拿到最后一个球的一方为负方(输方)
请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A是否能赢?
程序运行时,从标准输入获得数据,其格式如下:
先是一个整数n(n<100),表示接下来有n个整数。然后是n个整数,每个占一行(整数<10000),表示初始球数。
程序则输出n行,表示A的输赢情况(输为0,赢为1)。
例如1,用户输入:
4
1
2
10
18
则程序应该输出:
0
1
1
0
例如2,用户输入:
10
33
89
17
39
150
15
23
34
36
37
则程序应该输出: 0 1 1 1 1 1 1 1 1 0
解题思路:
列出当n分为为:1, 2, 3, 4, 5, 6, 7, 8, 9, 10 这几种情况时,A 的输赢情况?
仔细分析会发现,当有n个小球时,此时A的输赢状态与 n-8, n-7, n-3, n-1时的输赢情况有关。
明显是一个“动态规划问题(DP)”。
源码:
方法一: 1.递归求解
import java.util.Scanner;
public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int nums[] = new int[n]; for (int i = 0; i < n; i++) { nums[i] = sc.nextInt(); } // 递归 for (int i = 0; i < n; i++) { if (recursion(nums[i])) { System.out.println(1); } else { System.out.println(0); } } }
private static boolean recursion(int n) { if (n == 1) return false; if (n > 8 && recursion(n-8) == false) return true; if (n > 7 && recursion(n-7) == false) return true; if (n > 3 && recursion(n-3) == false) return true; if (n > 1 && recursion(n-1) == false) return true; return false; } }
方法二: 1.动态规划求解
import java.util.Scanner;
public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int nums[] = new int[n]; for (int i = 0; i < n; i++) { nums[i] = sc.nextInt(); } // DP 求解 int dp[] = new int[10001]; dp[1] = dp[3] = dp[5] = dp[7] = -1; dp[2] = dp[4] = dp[6] = dp[8] = dp[9] = dp[10] = 1; for (int i = 11; i < dp.length; i++) { if (dp[i-8] == -1 || dp[i-7] == -1 || dp[i-3] == -1 || dp[i-1] == -1) dp[i] = 1; else dp[i] = -1; } for (int i = 0; i < n; i++) { if (dp[nums[i]] == 1) System.out.println(1); else System.out.println(0); } }
}
方法三: 1.记忆化搜索
import java.util.Scanner;
public class Main { // 构建 DP 数组 public static int dp[] = new int[10001];
public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int nums[] = new int[n]; for (int i = 0; i < n; i++) { nums[i] = sc.nextInt(); }
dp[1] = dp[3] = dp[5] = dp[7] = -1; dp[2] = dp[4] = dp[6] = dp[8] = dp[9] = dp[10] = 1;
for (int i = 0; i < n; i++) { if (serach(nums[i]) == 1) System.out.println(1);
else System.out.println(0); } }
private static int serach(int n) { if (dp[n] != 0) return dp[n]; if (n > 8 && serach(n - 8) == -1) return dp[n] = 1; if (n > 7 && serach(n - 7) == -1) return dp[n] = 1; if (n > 3 && serach(n - 3) == -1) return dp[n] = 1; if (n > 1 && serach(n - 1) == -1) return dp[n] = 1; return dp[n] = -1; } }