美团笔试4.8(部分题目)

文章介绍了两个编程问题,一是寻找一棵树中经过特定边的最长简单路径,使用深度优先遍历来解决,但未通过所有测试用例;二是求解水果打包的最小成本问题,提出了递归深度遍历和动态规划两种方法,但动态规划未给出完整解决方案。
摘要由CSDN通过智能技术生成

题目二

题目描述

/*
问题描述:
有一棵n个节点的树,有一条边被选定。 小美想知道对于所有经过这条选定边的所有树上简单路径,最长的那条有多长
一条简单的路径的长度指这条简单路径上的边的个数

输入描述:
第一行一个整数n,表示树的结点个数
第二行n-1 个整数,第i整数 pi: 表示节点i-1 和 pi 之间有一条边相连。
第三行两个整数 x,y,表示这条选定的边。保证这条边一定是树上的一条边。
对于全部数据,2<10e5, 1<=x,y<=n 。x !=y。保证输入数据正确描述一棵树,开且
(x y)是树上的一条边

输出描述:
输出一行,一个整数,表示所有经过选定边的树上简单路径中,最长的那条的长度
*/

思路

重点在于理解题意!!!

树回溯问题,分别求出两个端点除彼此端点(不走彼此端点)的最长路径,两端路径数目相加再加上由这两个端点组成的这一条路径,即为答案。

但是通过率为91%,没有全部通过

代码

import java.util.ArrayList;
import java.util.Scanner;
//通过率91%
public class Main {

    static int n, x, y; // n 表示节点数,x 和 y 表示所选边的两个端点
    static ArrayList<Integer>[] edges; // 定义邻接表存储图
    static boolean[] visited; // 标记当前节点是否已访问过
    static int pathMax; // 存储被删去的边左右两部分的最大深度

    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        edges = new ArrayList[n + 1];
        visited = new boolean[n + 1];
        //建立邻接表
        for (int i = 1; i <= n; i++) {
            edges[i] = new ArrayList<>();
        }
        for (int i = 1; i < n; i++) {
            int u = sc.nextInt();
            int v = i + 1;
            edges[u].add(v);
            edges[v].add(u);
        }

        //确定边
        x = sc.nextInt();
        y = sc.nextInt();
        sc.close();

        int res = 0;
        visited[y] = true;//确保不走y这个端点
        dfs(x,0);
        visited[y] = false;
        res +=pathMax;
        pathMax = 0;

        visited[x] = true;//确保不走x这个端点
        dfs(y,0);
        visited[x] = false;
        res += pathMax;

        System.out.println(res+1);//最后加上本身x,y这一条路径 res+1
    }

    /**
     * 深度优先遍历以u节点为起点的路径
     * @param u
     * @param depth
     */
    private static void dfs(int u,int depth) {
        visited[u] = true;
        pathMax = Math.max(pathMax,depth);
        for (int v : edges[u]) {
            if (!visited[v]) {
                dfs(v,depth + 1);
            }
        }
    }

}

题目三

题目描述

/*
小美不干外卖配送了,转行开了一家水果店。
一天她接到了一个大单,客户订购了 n 个水果,并且要求打包成多个果篮,一个果篮最多装 m 个水果。
为了包装方便,水果按从 1 到 n 编号,同一个果篮里装的水果编号必须是连续的。果篮的成本与容积成线性关系。为了估计容积,小美简单地用样本中点估计了一下。具体来说,假设一个果篮中装的最大的水果体积是 u,最小的是 v,那么这个果篮的成本就是 k × floor((u+v)/2) + s,其中 k 是果篮中装入水果的个数,s 是一个常数,floor(x) 是下取整函数,比如 floor(3.8)=3, floor(2)=2。
客户并没有规定果篮的数量,但是希望果篮的成本越小越好,毕竟买水果就很贵了。请求出小美打包这 n 个水果所用的最小花费。
输入描述
第一行三个正整数 n, m, s。意义如题面所示。
第二行 n 个正整数 a1, a2, ..., an,表示每个水果的体积。
对于全部数据,1 ≤ n ≤ 1e4,   1 ≤ m ≤ 1e3,   m ≤ n,   1 ≤ ai, s ≤ 1e4。
输出描述
输出一个整数,表示打包这 n 个水果果篮的最小成本。
样例输入
6 4 3
1 4 5 1 4 1
样例输出
21
*/

思路

思路

1. 递归 深度遍历

时间复杂度会很高,估计不能全通过!!!

每个篮子存放的数目为1,2,... , m 。共m种可能;每一种情况下依次再递归剩下的水果;最后取最小的结果。

2.动态规划

也可用动态规划,没搞出来,后边更新

代码

import java.util.Scanner;

public class Main {
    //水果打包
    static int res = Integer.MAX_VALUE;
    static int m;
    static int s;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        m = scanner.nextInt();
        s = scanner.nextInt();
        int[] fruits = new int[n];
        for (int i = 0; i < n; i++) {
            fruits[i] = scanner.nextInt();
        }
        dfs(fruits,0,0);
        System.out.println(res);
    }
    public static void dfs(int[] fruits,int index,int preCost){
        if(preCost > res) return;//剪枝操作
        if(index >= fruits.length){
            res = preCost;
            return;
        }
        int tempCost = 0;
        int theBig = Integer.MIN_VALUE;//保存装入的水果里最大水果的体积
        int theSmall = Integer.MAX_VALUE;//保存装入的水果里最小水果的体积
        int count = 0;//装入水果的个数
        for (int i = index; i < Math.min(index + m,fruits.length); i++) {
            theBig = Math.max(theBig,fruits[i]);
            theSmall = Math.min(theSmall,fruits[i]);
            count++;

            tempCost = count * ((theBig + theSmall)/2) + s;
            dfs(fruits,i+1,preCost + tempCost);
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值