1.打死怪兽的概率 给定 3 个参数,N,M,K,表示怪兽有 N 滴血,英雄每攻击一次,怪兽会在 0~M 范围等概率流失血量。 在 K 次打击后,英雄把怪兽砍死的概率是多少?
暴力递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static double right (int N, int M, int K) { if (N < 1 || M < 1 || K < 1 ) { return 0 ; } long all = (long ) Math.pow(M + 1 , K); long kill = process(K, M, N); return (double ) ((double ) kill / (double ) all); } public static long process (int times, int M, int hp) { if (times == 0 ) { return hp <= 0 ? 1 : 0 ; } if (hp <= 0 ) { return (long ) Math.pow(M + 1 , times); } long ways = 0 ; for (int i = 0 ; i <= M; i++) { ways += process(times - 1 , M, hp - i); } return ways; }
动态规划 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public static double dp (int N, int M, int K) { if (N < 1 || M < 1 || K < 1 ) { return 0 ; } long all = (long ) Math.pow(M + 1 , K); long [][] dp = new long [K + 1 ][N + 1 ]; dp[0 ][0 ] = 1 ; for (int times = 1 ; times <= K; times++) { dp[times][0 ] = (long ) Math.pow(M + 1 , times); for (int hp = 1 ; hp <= N; hp++) { long ways = 0 ; for (int i = 0 ; i <= M; i++) { if (hp - i >= 0 ) { ways += dp[times - 1 ][hp - i]; } else { ways += (long ) Math.pow(M + 1 , times - 1 ); } } dp[times][hp] = ways; } } long kill = dp[K][N]; return (double ) ((double ) kill / (double ) all); }
动态规划(斜率优化) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static double dp (int N, int M, int K) { if (N < 1 || M < 1 || K < 1 ) { return 0 ; } long all = (long ) Math.pow(M + 1 , K); long [][] dp = new long [K + 1 ][N + 1 ]; dp[0 ][0 ] = 1 ; for (int times = 1 ; times <= K; times++) { dp[times][0 ] = (long ) Math.pow(M + 1 , times); for (int hp = 1 ; hp <= N; hp++) { dp[times][hp] = dp[times][hp - 1 ] + dp[times - 1 ][hp]; if (hp - 1 - M >= 0 ) { dp[times][hp] -= dp[times - 1 ][hp - 1 - M]; } else { dp[times][hp] -= Math.pow(M + 1 , times - 1 ); } } } long kill = dp[K][N]; return (double ) ((double ) kill / (double ) all); }
2.零钱兑换问题4-面值无限张-最少货币张数 面值数组 arr,其中都是正数且没有重复,每个值都认为是一种面值且张数是无限的。 给定一个正数 aim,返回能组成 aim 的最少货币张数。
暴力递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static int minCoins (int [] arr, int aim) { return process(arr, 0 , aim); } public static int process (int [] arr, int index, int rest) { if (index == arr.length) { return rest == 0 ? 0 : Integer.MAX_VALUE; } else { int ans = Integer.MAX_VALUE; for (int zhang = 0 ; zhang * arr[index] <= rest; zhang++) { int next = process(arr, index + 1 , rest - zhang * arr[index]); if (next != Integer.MAX_VALUE) { ans = Math.min(ans, zhang + next); } } return ans; } }
动态规划 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public static int dp (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 j = 1 ; j <= aim; j++) { dp[N][j] = Integer.MAX_VALUE; } for (int index = N - 1 ; index >= 0 ; index--) { for (int rest = 0 ; rest <= aim; rest++) { int ans = Integer.MAX_VALUE; for (int zhang = 0 ; zhang * arr[index] <= rest; zhang++) { int next = dp[index + 1 ][rest - zhang * arr[index]]; if (next != Integer.MAX_VALUE) { ans = Math.min(ans, zhang + next); } } dp[index][rest] = ans; } } return dp[0 ][aim]; }
动态规划(斜率优化) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static int dp (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 j = 1 ; j <= aim; j++) { dp[N][j] = Integer.MAX_VALUE; } for (int index = N - 1 ; index >= 0 ; index--) { for (int rest = 0 ; rest <= aim; rest++) { dp[index][rest] = dp[index + 1 ][rest]; if (rest - arr[index] >= 0 && dp[index][rest - arr[index]] != Integer.MAX_VALUE) { dp[index][rest] = Math.min(dp[index][rest], dp[index][rest - arr[index]] + 1 ); } } } return dp[0 ][aim]; }
3.拆分整数 给定一个正整数 n,将其拆分为 1 个或多个正整数的和,要求拆开的数后面的不能比前面的数小。返回最多有多少种拆分方式。
暴力递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public static int ways (int n) { if (n < 0 ) { return 0 ; } if (n == 1 ) { return 1 ; } return process(1 , n); } public static int process (int pre, int rest) { if (rest == 0 ) { return 1 ; } if (pre > rest) { return 0 ; } int ways = 0 ; for (int first = pre; first <= rest; first++) { ways += process(first, rest - first); } return ways; }
动态规划 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static int dp (int n) { if (n < 0 ) { return 0 ; } if (n == 1 ) { return 1 ; } int [][] dp = new int [n + 1 ][n + 1 ]; for (int pre = 1 ; pre <= n; pre++) { dp[pre][0 ] = 1 ; dp[pre][pre] = 1 ; } for (int pre = n - 1 ; pre >= 1 ; pre--) { for (int rest = pre + 1 ; rest <= n; rest++) { int ways = 0 ; for (int first = pre; first <= rest; first++) { ways += dp[first][rest - first]; } dp[pre][rest] = ways; } } return dp[1 ][n]; }
动态规划(斜率优化) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static int dp2 (int n) { if (n < 0 ) { return 0 ; } if (n == 1 ) { return 1 ; } int [][] dp = new int [n + 1 ][n + 1 ]; for (int pre = 1 ; pre <= n; pre++) { dp[pre][0 ] = 1 ; dp[pre][pre] = 1 ; } for (int pre = n - 1 ; pre >= 1 ; pre--) { for (int rest = pre + 1 ; rest <= n; rest++) { dp[pre][rest] = dp[pre + 1 ][rest]; dp[pre][rest] += dp[pre][rest - pre]; } } return dp[1 ][n]; }