蓝桥杯2012年 取球游戏(博弈论三种解法)

蓝桥杯2012年 取球游戏(博弈论三种解法)

题目:

题目描述
今盒子里有 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()]);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值