【Java】博弈论三种解法

题目描述

今盒子里有 n 个小球,A、B 两人轮流从盒中取球,每个人都可以看到另一>个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会>做出错误的判断。

我们约定:
每个人从盒子中取出的球的数目必须是:1,3,7 或者 8 个。轮到某一方取>球时不能弃权!A 先取球,然后双方交替取球,直到取完。被迫拿到最后一>个球的一方为负方(输方)

请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A 是否>能赢?

输入描述
先是一个整数 n (n<100),表示接下来有 n 个整数。

然后是 n 个整数,每个占一行(整数< 10^4),表示初始球数。

输出描述
程序则输出 n 行,表示 A 的输赢情况(输为 0,赢为 1)。

输入输出样例
示例
输入



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()]);
        }
    }
}

作者:struggle
链接:https://leetcode.cn/circle/discuss/D6ZYWa/

猜你喜欢

转载自blog.csdn.net/JSPSEO/article/details/125164643
今日推荐