美团笔试题
1. 合并金币问题
动态规划,dp[j][i] 表示合并第j个到第i个金币的总花费(j>=i 从前往后的顺序合并)
j==i 时候 dp=0 就一个金币,无需合并 ;
i==j+1 时候 dp=相邻两个金币和 相邻;
其他情况 dp[j][i] = min{ dp[j][k] + dp[k+1][i] + sum } j<=k<i ,分别合并此区间内左区间dp[j][k],右区间 dp[k+1][i] ,最后合并左右区间还需花费 金币j到i的和 sum
import java.util.Scanner; /** * @author zzm * @data 2020/4/17 21:18 * 有 N 堆金币排成一排,第 i 堆中有 C[i] 块金币。每次合并都会将相邻的两堆金币合并为一堆,成本为这两堆金币块数之和。 * 经过N-1次合并,最终将所有金币合并为一堆。请找出将金币合并为一堆的最低成本。 * 其中,1 <= N <= 30,1 <= C[i] <= 100 * 输入描述: * 第一行输入一个数字 N 表示有 N 堆金币 * 第二行输入 N 个数字表示每堆金币的数量 C[i] * 输出描述: * 输出一个数字 S 表示最小的合并成一堆的成本 */ public class MTmergeCoin { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int len = Integer.parseInt(scanner.nextLine()); String s = scanner.nextLine(); String[] split = s.split(" "); int[] coins = new int[len]; int[] sum = new int[len + 1]; for (int i = 0; i < len; i++) { coins[i] = Integer.parseInt(split[i]); sum[i + 1] = coins[i] + sum[i]; } int[][] dp = new int[len + 1][len + 1]; for (int i = 1; i <= len; i++) { for (int j = i; j > 0; j--) { if (i == j) dp[i][j] = 0; else if (j == i - 1) dp[j][i] = coins[i - 1] + coins[i - 2]; else { dp[j][i] = Integer.MAX_VALUE; for (int k = j; k < i; k++) { dp[j][i] = Math.min(dp[j][i], dp[j][k] + dp[k + 1][i] + sum[i] - sum[j - 1]); } } } } System.out.println(dp[1][len]); } }
2. 迷宫最小路径问题(动态规划)
import java.util.*; /** * @author zzm * @data 2020/4/19 22:10 * 给定一个包含非负整数的 M x N 迷宫,请找出一条从左上角到右下角的路径,使得路径上的数字总和最小。每次只能向下或者向右移动一步。 * 输入描述: * 第一行包含两个整数M和N,以空格隔开,1≤N≤10,1≤N≤10。 * 接下来的M行中,每行包含N个数字 。 * 输出描述: * 找出总和最小的路径,输出路径上的数字总和。 */ public class MTmaze { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int row = scanner.nextInt(); int col = scanner.nextInt(); int[][] maze = new int[row + 1][col + 1]; int temp; for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { temp = scanner.nextInt(); if(i==1){ maze[i][j]=maze[i][j-1]+temp; continue; } if(j==1) { maze[i][j]=maze[i-1][j]+temp; continue; } maze[i][j] = Math.min(maze[i - 1][j], maze[i][j - 1]) + temp; } } scanner.close(); System.out.println(maze[row][col]); } }
3. 飞船吸收能量(深度优先遍历)
import java.util.*; /** * @author zzm * @data 2020/4/19 22:28 * 小团在一次星际旅行中,耗尽了飞船的能量,迷失在了空间魔方中,空间魔方中有N*N*N个能量粒子。美团云AI迅速帮小团分析出了空间魔方的能量分布图。 * 已知小团的飞船被困在能量值最高的点,能量值最高点有且只有一个。飞船每到达一个能量粒子就会吸收对应粒子的能量,该粒子会坍缩成小黑洞,飞船不可到达。 * 小团驾驶的飞船只能从高能粒子驶向低能粒子,且每次只能从6个方向中选择一个前进。(±x,±y,±z)。 * 请帮助帮小团吸收最高的能量值。 * 输入描述: * N(0≤N≤8) * N*N*N行空间能量数据,格式为:X Y Z P,XYZ表示点坐标,P表示空间能量分布(0≤P) * 输出描述: * 输出一个整数,表示可吸收到的最高的能量值 */ public class MTmaxEnergy { static int res = 0, n = 0; static int[][][] energy; static boolean[][][] used; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); n = Integer.parseInt(scanner.nextLine()); energy = new int[n][n][n]; used = new boolean[n][n][n]; int maxEnergy = -1, x = 0, y = 0, z = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) for (int k = 0; k < n; k++) { int temp = Integer.parseInt(scanner.nextLine().split(" ")[3]); energy[i][j][k] = temp; if (temp > maxEnergy) { maxEnergy = temp; x = i; y = j; z = k; } } scanner.close(); dfs(x, y, z, 0,Integer.MAX_VALUE); System.out.println(res); } private static void dfs(int x, int y, int z, int totle,int pre) { if (x < 0 || x == n || y < 0 || y == n || z < 0 || z == n || used[x][y][z] || pre<=energy[x][y][z]) return; int now = energy[x][y][z]; totle += now; used[x][y][z] = true; dfs(x - 1, y, z, totle,now); dfs(x + 1, y, z, totle,now); dfs(x, y - 1, z, totle,now); dfs(x, y + 1, z, totle,now); dfs(x, y, z - 1, totle,now); dfs(x, y, z + 1, totle,now); used[x][y][z] = false; res = Math.max(res, totle); } }
4. 使用最少数量代金券完成0元购物(动态规划,dp[总价格])
import java.util.*; /** * @author zzm * @data 2020/4/19 20:10 * 近期某商场由于周年庆,开启了“0元购”活动。活动中,消费者可以通过组合手中的代金券,实现0元购买指定商品。 * 聪明的小团想要用算法来帮助他快速计算:对于指定价格的商品,使用代金券凑出其价格即可,但所使用的代金券总面额不可超过商品价格。 * 由于代金券数量有限,使用较少的代金券张数则可以实现价值最大化,即最佳优惠。 * 假设现有100元的商品,而代金券有50元、30元、20元、5元四种,则最佳优惠是两张50元面额的代金券;而如果现有65元的商品,则最佳优惠是两张30元代金券以及一张5元代金券。 * 请你帮助小团使用一段代码来实现代金券计算。 * <p> * 输入描述: * 多组输入输出,读到s=0时结束 * 输入可以有多个测试样例,每个测试由两行组成。 * 其中第一行包含一个整数P,表示商品的价格,1≤P≤10000;输入P为0时表示结束。 * 第二行包含若干整数,使用空格分割。其中第一个整数N(1≤N≤20)表示有多少种代金券,其后跟随M个整数,表示手中持有的代金券面额(1≤N≤1000),每种代金券数量不限。 * <p> * 输出描述: * 找到最少张数的代金券,使其面额恰好等于商品价格。输出所使用的代金券数量; * 如果有多个最优解,只输出其中一种即可; * 如果无解,则需输出“Impossible”。 * <p> * 输入例子1: * 65 * 4 50 30 20 5 * 0 * 输出例子1: * 3 */ public class MTzeroshopping { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); List<Integer> prices = new ArrayList<>(); List<int[]> tickets = new ArrayList<>(); int num; while ((num = Integer.parseInt(scanner.nextLine())) != 0) { prices.add(num); String[] split = scanner.nextLine().split(" "); int len = Integer.parseInt(split[0]); int[] ints = new int[len]; for (int i = 0; i < len; i++) ints[i] = Integer.parseInt(split[i + 1]); tickets.add(ints); } scanner.close(); for (int i = 0; i < prices.size(); i++) { int[] dp = new int[prices.get(i)+1]; helper(dp,prices.get(i),tickets.get(i)); int res = dp[prices.get(i)]; if(res>=0) System.out.println(res); else System.out.println("Impossible"); } } private static int helper(int[] dp, int price, int[] ticket) { if (price < 0) return -1; if (price == 0) return 0; if (dp[price] != 0) return dp[price]; int min = Integer.MAX_VALUE; for (int tic : ticket) { int dpL = helper(dp, price - tic, ticket); if (dpL >= 0) min = Math.min(min, dpL); } dp[price] = (min == Integer.MAX_VALUE) ? -1 : min + 1; return dp[price]; } }

浙公网安备 33010602011771号