diff --git a/src/leo/class22/KillMonster.java b/src/leo/class22/KillMonster.java index c352d18..1b20457 100644 --- a/src/leo/class22/KillMonster.java +++ b/src/leo/class22/KillMonster.java @@ -24,12 +24,12 @@ public class KillMonster { } private static long process(int hp, int m, int rest) { + if (rest == 0) { + return hp <= 0 ? 1 : 0; + } if (hp <= 0) { return (long) Math.pow(m + 1, rest); } - if (rest == 0) { - return hp == 0 ? 1 : 0; - } int ans = 0; for (int i = 0; i <= m; i++) { ans += process(hp - i, m, rest - 1); @@ -40,4 +40,72 @@ public class KillMonster { } + static class Dp { + public static double kill(int n, int m, int k) { + if (n < 1 || m < 1 || k < 1) { + return 0; + } + long[][] dp = new long[n + 1][k + 1]; + dp[0][0] = 1; + for (int hp = 1; hp <= n; hp++) { + for (int rest = 1; rest <= k; rest++) { + dp[0][rest] = (long) Math.pow(m + 1, rest); + long ans = 0; + for (int i = 0; i <= m; i++) { + if (hp - i <= 0) { + ans += (long) Math.pow(m + 1, rest - 1); + } else { + ans += dp[hp - i][rest - 1]; + } + } + dp[hp][rest] = ans; + } + } + return dp[n][k] / Math.pow(m + 1, k); + } + } + static class OptDp{ + public static double kill(int n, int m, int k) { + if (n < 1 || m < 1 || k < 1) { + return 0; + } + long[][] dp = new long[n + 1][k + 1]; + dp[0][0] = 1; + for (int hp = 1; hp <= n; hp++) { + for (int rest = 1; rest <= k; rest++) { + dp[0][rest] = (long) Math.pow(m + 1, rest); + dp[hp][rest] = dp[hp][rest - 1] + dp[hp-1][rest]; + if (hp - m - 1 >=0) { + dp[hp][rest] -= dp[hp - m - 1][rest - 1]; + }else{ + dp[hp][rest] -= (long) Math.pow(m + 1, rest - 1); + } + + } + } + return dp[n][k] / Math.pow(m + 1, k); + } + } + + public static void main(String[] args){ + int NMax = 10; + int MMax = 10; + int KMax = 10; + int testTime = 200; + System.out.println("测试开始"); + for (int i = 0; i < testTime; i++) { + int N = (int) (Math.random() * NMax); + int M = (int) (Math.random() * MMax); + int K = (int) (Math.random() * KMax); + double ans1 = Recursion.kill(N, M, K); + double ans2 = Dp.kill(N, M, K); + double ans3 = OptDp.kill(N, M, K); + if (ans1 != ans2 || ans1 != ans3) { + System.out.println("Oops!"); + break; + } + } + System.out.println("测试结束"); + + } } diff --git a/src/leo/class22/MinCoinsNoLimit.java b/src/leo/class22/MinCoinsNoLimit.java new file mode 100644 index 0000000..47ed236 --- /dev/null +++ b/src/leo/class22/MinCoinsNoLimit.java @@ -0,0 +1,140 @@ +package leo.class22; + +import class22.Code02_MinCoinsNoLimit; + +/** + * @author Leo + * @ClassName MinCoinsNoLimit + * @DATE 2021/1/15 1:39 下午 + * @Description + * + * arr是面值数组,其中的值都是正数且没有重复。再给定一个正数aim。 + * 每个值都认为是一种面值,且认为张数是无限的。 + * 返回组成aim的最少货币数 + */ +public class MinCoinsNoLimit { + + static class Recursion{ + public static int minCoins(int[] arr, int aim) { + + return process(arr, aim, 0); + } + + private static int process(int[] arr, int rest, int i) { + if (i == arr.length) { + return rest == 0 ? 0 : Integer.MAX_VALUE; + } + int ans = Integer.MAX_VALUE; + for (int z = 0; z * arr[i] <= rest; z++) { + int next = process(arr, rest - z * arr[i], i + 1); + if (next != Integer.MAX_VALUE) { + ans = Math.min(ans, next + z); + } + } + return ans; + } + } + + + static class Dp { + public static int minCoins(int[] arr, int aim) { + if (aim == 0) { + return 0; + } + int n = arr.length; + int[][] dp = new int[n + 1][aim + 1]; + dp[n][0] = 0; + for (int i = 1; i <= aim; i++) { + dp[n][i] = Integer.MAX_VALUE; + } + for (int i = n - 1; i >= 0; i--) { + for (int rest = 0; rest <= aim; rest++) { + int ans = Integer.MAX_VALUE; + for (int z = 0; z * arr[i] <= rest; z++) { + int next = dp[i + 1][rest - z * arr[i]]; + if (next != Integer.MAX_VALUE) { + ans = Math.min(ans, next + z); + } + } + dp[i][rest] = ans; + } + } + return dp[0][aim]; + } + } + + static class OptDp{ + public static int minCoins(int[] arr, int aim) { + if (aim == 0) { + return 0; + } + int n = arr.length; + int[][] dp = new int[n + 1][aim + 1]; + dp[n][0] = 0; + for (int i = 1; i <= aim; i++) { + dp[n][i] = Integer.MAX_VALUE; + } + for (int i = n - 1; i >= 0; i--) { + for (int rest = 0; rest <= aim; rest++) { + dp[i][rest] = dp[i + 1][rest]; + if (rest - arr[i] >= 0 && dp[i][rest - arr[i]] != Integer.MAX_VALUE) { + dp[i][rest] = Math.min(dp[i][rest], dp[i][rest - arr[i]] + 1); + } + } + } + return dp[0][aim]; + + + } + } + + // 为了测试 + public static int[] randomArray(int maxLen, int maxValue) { + int N = (int) (Math.random() * maxLen); + int[] arr = new int[N]; + boolean[] has = new boolean[maxValue + 1]; + for (int i = 0; i < N; i++) { + do { + arr[i] = (int) (Math.random() * maxValue) + 1; + } while (has[arr[i]]); + has[arr[i]] = true; + } + return arr; + } + + // 为了测试 + public static void printArray(int[] arr) { + for (int i = 0; i < arr.length; i++) { + System.out.print(arr[i] + " "); + } + System.out.println(); + } + + // 为了测试 + public static void main(String[] args) { + int maxLen = 20; + int maxValue = 30; + int testTime = 300000; + System.out.println("功能测试开始"); + for (int i = 0; i < testTime; i++) { + int N = (int) (Math.random() * maxLen); + int[] arr = randomArray(N, maxValue); + int aim = (int) (Math.random() * maxValue); + int ans1 = Recursion.minCoins(arr, aim); + int ans2 = Dp.minCoins(arr, aim); + int ans3 = OptDp.minCoins(arr, aim); + if (ans1 != ans2 || ans1 != ans3) { + System.out.println("Oops!"); + printArray(arr); + System.out.println(aim); + System.out.println("--0---"); + System.out.println(ans1); + System.out.println(ans2); + System.out.println(ans3); + break; + } + } + System.out.println("功能测试结束"); + } + +}