美团笔试题

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

}

 

  

posted @ 2020-04-18 10:06  zzmhust  阅读(859)  评论(0)    收藏  举报