You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
3.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_08_5_week;
// 来自学员面试
// nim博弈
// 有a块草莓蛋糕有b块芝士蛋糕两人轮流拿蛋糕
// 每次不管是谁只能选择在草莓蛋糕和芝士蛋糕中拿一种
// 拿的数量在1~m之间随意
// 谁先拿完最后的蛋糕谁赢
// 返回先手赢还是后手赢
public class Code01_Cakes {
// 草莓蛋糕a块
// 巧克力蛋糕b块
// 每次可以在任意一种上拿1~m块
// 返回谁会赢,"先手" or "后手"
public static String[][][] dp = new String[101][101][101];
// 暴力方法
// 为了验证
public static String whoWin1(int a, int b, int m) {
if (m >= Math.max(a, b)) { // nim博弈
return a != b ? "先手" : "后手";
}
if (a == b) {
// 蛋糕一样多
// 先手必输,因为先手不管拿什么,拿多少
// 后手都在另一堆上,拿同样多的蛋糕
// 继续让两堆蛋糕一样多
// 最终先手必输,后手必赢
return "后手";
}
if (dp[a][b][m] != null) {
return dp[a][b][m];
}
String ans = "后手";
for (int pick = 1; pick <= Math.min(a, m); pick++) {
if (whoWin1(a - pick, b, m).equals("后手")) {
ans = "先手";
}
if (ans.equals("先手")) {
break;
}
}
for (int pick = 1; pick <= Math.min(b, m); pick++) {
if (whoWin1(a, b - pick, m).equals("后手")) {
ans = "先手";
}
if (ans.equals("先手")) {
break;
}
}
dp[a][b][m] = ans;
return ans;
}
// 正式解法
// 时间复杂度O(1)
// 先看nim博弈
public static String whoWin2(int a, int b, int m) {
if (m >= Math.max(a, b)) { // nim博弈
return a != b ? "先手" : "后手";
}
// m < max(a,b)
if (a == b) {
// 蛋糕一样多
// 先手必输,因为先手不管拿什么,拿多少
// 后手都在另一堆上,拿同样多的蛋糕
// 继续让两堆蛋糕一样多
// 最终先手必输,后手必赢
return "后手";
}
// 如果 a != b
// 关注a和b的差值
// 谁最先遇到差值为0谁输
// 那么这就是巴什博奕
// 差值蛋糕数量共rest个。
// 每次从最少取1个最多取m个最后取光的人取胜。
// 如果rest=(m+1)*k + s (s!=0) 那么先手一定必胜
// 因为第一次取走s个
// 接下来无论对手怎么取,
// 先手都能保证取到所有(m+1)倍数的点,
// 那么循环下去一定能取到差值最后一个。
int rest = Math.max(a, b) - Math.min(a, b);
return rest % (m + 1) != 0 ? "先手" : "后手";
}
public static void main(String[] args) {
int V = 100;
System.out.println("测试开始");
for (int a = 0; a <= V; a++) {
for (int b = 0; b <= V; b++) {
for (int m = 0; m <= V; m++) {
String ans1 = whoWin1(a, b, m);
String ans2 = whoWin2(a, b, m);
if (!ans1.equals(ans2)) {
System.out.println("出错了!");
System.out.println("a : " + a);
System.out.println("b : " + b);
System.out.println("m : " + m);
System.out.println("ans1 : " + ans1);
System.out.println("ans2 : " + ans2);
break;
}
}
}
}
System.out.println("测试结束");
}
}