华为OD机试 - 快递员的烦恼 - 动态规划(Java 2024 C卷 200分)

在这里插入图片描述

华为OD机试 2024C卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试(JAVA)真题(A卷+B卷+C卷)》

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

快递公司每日早晨,给每位快递员推送需要淡到客户手中的快递以及路线信息,快递员自己又查找了一些客户与客户之间的路线距离信息,请你依据这些信息,给快递员设计一条最短路径,告诉他最短路径的距离。

不限制快递包裹送到客户手中的顺序,但必须保证都送到客户手中;

用例保证一定存在投递站到每位客户之间的路线,但不保证客户与客户之间有路线,客户位置及投递站均允许多次经过;

所有快递送完后,快递员需回到投递站;

二、输入描述

首行输入两个正整数n、m.

接下来n行,输入快递公司发布的客户快递信息,格式为:客户id 投递站到客户之间的距离distance

再接下来的m行,是快递员自行查找的客户与客户之间的距离信息,格式为:客户1id 客户2id distance

在每行数据中,数据与数据之间均以单个空格分割规格:

0 <=n <= 10 0 <= m <= 10 0 < 客户id <= 1000 0 < distance <= 10000

三、输出描述

最短路径距离,如无法找到,请输出-1

四、解题思路

可以利用图的遍历方法,特别是基于图的最短路径问题。这个问题实际上是一个变种的旅行销售员问题(TSP),需要找到一个最短的路径,让快递员从投递站出发,经过所有客户位置至少一次,然后返回投递站。我们可以通过以下步骤来解决这个问题:

解题思路:

  1. 首先将所有的点(包括投递站和客户)以及它们之间的距离建模成一个完全图。对于客户与客户之间没有直接距离的情况,可以考虑用一个很大的数(如无穷)来表示两点之间无法直接到达。
  2. 由于图中点的数量较少(最多10个客户加一个投递站),我们可以使用Floyd-Warshall算法预处理任意两点间的最短路径。这个算法能在多项式时间内处理完所有点对的最短路径问题。
  3. 在获取了所有点对间的最短路径后,使用动态规划解决TSP问题。状态dp[mask][i]表示已访问的客户集合为mask,当前在客户i的最短路径长度。转移方程需要考虑从任一客户j到i的转移,更新状态。
  4. 计算总路程:计算包括从投递站出发、访问所有客户以及返回投递站的总最短路径长度。
  5. 输出结果:输出计算出的最短路径长度,如果存在无法到达的情况,输出-1。

五、动态规划

动态规划(Dynamic Programming, DP)是一种算法设计技术,用于解决具有重叠子问题和最优子结构的问题。它通常用于求解优化问题。在动态规划中,复杂问题被分解为更小的子问题,这些子问题被逐一解决,并将结果存储起来(称为 “记忆化”),以避免重复计算相同的问题。

1、动态规划的两个主要特征

  1. 重叠子问题:原问题可以分解成许多更小的子问题,且子问题会重复出现。例如,在斐波那契数列的计算中,求解 fib(5) 需要求解 fib(4) 和 fib(3),而求解 fib(4) 又需要求解 fib(3) 和 fib(2),这里的 fib(3) 就是一个重叠子问题。
  2. 最优子结构:原问题的最优解包含其子问题的最优解。即一旦我们得到了子问题的最优解,就可以利用这些解构造原问题的最优解。例如,在计算最短路径问题中,从点A到点C的最短路径如果经过点B,则从点A到点B的路径也应是最短路径。

2、动态规划的基本步骤

  1. 定义状态:将问题的解定义成状态,通常是一个数组或矩阵。
  2. 设定状态转移方程:找出状态之间的关系,如何从一个或多个较小的状态推导出当前状态。
  3. 确定边界条件:这些是最小子问题的解,它们作为构建更复杂解答的基础。
  4. 计算并存储解:按照顺序从最小的子问题开始解决,存储它们的结果,逐步构建最终的解决方案。

3、常见可以用动态规划解决的问题类型:

  1. 斐波那契数列:计算第n个斐波那契数。
  2. 0/1背包问题:给定一组物品和一个背包的容量,选择其中若干物品装入背包,使得装入的总价值最大,且总重量不超过背包容量。
  3. 最长公共子序列:找出两个序列共有的最长子序列的长度。
  4. 最短路径问题(如Floyd-Warshall算法):在给定的图中找到所有点对之间的最短路径。
  5. 硬币找零问题:给定不同面额的硬币和一个总金额,找出组成该金额的最少硬币数量。
  6. 编辑距离(Levenshtein距离):计算从一个字符串转换成另一个字符串最少的插入、删除和替换操作数。
  7. 旅行销售员问题(TSP):在加权图中找到访问每个顶点恰好一次并返回起点的最短回路。
  8. 最长递增子序列:在一个数列中找到一个最长的递增子序列的长度。

六、Java算法源码

public class Test02 {
    /**
     * 2 1
     * 1 1000
     * 2 1200
     * 1 2 300
     *
     * 快递员先把快递送到客户1手中,接下来直接走客户1到客户2之间的直通线路,最后走投递站和客户2之间的路,回到投递站,距离为1000+300+1200= 2500
     */
    static final int MAX = 10000; // 一个比较大的数,用于表示无法直接到达
    static final int MAX_CLIENTS = 11; // 最多10个客户加上一个投递站

    public static int optimizeDelivery(int n, int m, int[][] deliveryInfo, int[][] customerDistances) {
        int V = n + 1; // 顶点总数,包括投递站和所有客户
        int[][] dist = new int[V][V]; // 存储最短路径的距离数组

        // 初始化距离数组
        for (int i = 0; i < V; i++) {
            Arrays.fill(dist[i], MAX);
            dist[i][i] = 0; // 到自己的距离是0
        }

        // 填充投递站到客户的距离
        for (int[] info : deliveryInfo) {
            int clientId = info[0];
            int distance = info[1];
            dist[0][clientId] = distance;
            dist[clientId][0] = distance;
        }

        // 填充客户间的距离
        for (int[] custDist : customerDistances) {
            int cust1 = custDist[0];
            int cust2 = custDist[1];
            int distance = custDist[2];
            dist[cust1][cust2] = Math.min(dist[cust1][cust2], distance); // 取最小值,考虑重复边
            dist[cust2][cust1] = Math.min(dist[cust2][cust1], distance);
        }

        // 使用Floyd-Warshall算法计算所有点对的最短路径
        for (int k = 0; k < V; k++) {
            for (int i = 0; i < V; i++) {
                for (int j = 0; j < V; j++) {
                    if (dist[i][k] < MAX && dist[k][j] < MAX) {
                        dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
                    }
                }
            }
        }

        // 解决TSP问题
        int ALL_VISITED = (1 << n) - 1; // 全部访问过的状态
        int[][] dp = new int[1 << n][n];
        for (int[] row : dp) {
            Arrays.fill(row, MAX);
        }

        // 初始化,从投递站到所有客户的起始距离
        for (int i = 1; i < n; i++) {
            dp[1 << i][i] = dist[0][i + 1];
        }

        // 动态规划填表
        for (int mask = 0; mask <= ALL_VISITED; mask++) {
            for (int i = 0; i < n; i++) {
                if ((mask & (1 << i)) != 0) { // 如果i已访问
                    for (int j = 0; j < n; j++) {
                        if ((mask & (1 << j)) == 0) { // 如果j未访问
                            int nextMask = mask | (1 << j);
                            dp[nextMask][j] = Math.min(dp[nextMask][j], dp[mask][i] + dist[i + 1][j + 1]);
                        }
                    }
                }
            }
        }

        // 从任何客户返回投递站的最短路径
        int minPath = MAX;
        for (int i = 0; i < n; i++) {
            minPath = Math.min(minPath, dp[ALL_VISITED][i] + dist[i + 1][0]);
        }

        return minPath == MAX ? -1 : minPath;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int[][] deliveryInfo = new int[n][2];
        for (int i = 0; i < n; i++) {
            deliveryInfo[i][0] = scanner.nextInt();
            deliveryInfo[i][1] = scanner.nextInt();
        }
        int[][] customerDistances = new int[m][3];
        for (int i = 0; i < m; i++) {
            customerDistances[i][0] = scanner.nextInt();
            customerDistances[i][1] = scanner.nextInt();
            customerDistances[i][2] = scanner.nextInt();
        }
        int result = optimizeDelivery(n, m, deliveryInfo, customerDistances);
        System.out.println(result);
    }
}

七、效果展示

1、输入

2 1
1 1000
2 1200
1 2 300

2、输出

2500

3、说明

快递员先把快递送到客户1手中,接下来直接走客户1到客户2之间的直通线路,最后走投递站和客户2之间的路,回到投递站,距离为1000+300+1200= 2500

在这里插入图片描述


🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 2024 C卷 200分)

🏆本文收录于,华为OD机试(JAVA)真题(A卷+B卷+C卷)

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

  • 15
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
华为OD机试是针对华为公司招聘和选拔人才的一种机试方式,其中有一个题目是关于快递业务站。快递业务站是为了提供快递服务的地点,通常由快递公司设立。下面是我对于华为OD机试快递业务站的问题的回答。 快递业务站是快递业务的办理和管理中心,主要负责快递包裹的收取、拣、存储以及派送等工作。快递业务站是快递公司与客户之间的桥梁,通过它可以方便地将包裹送达到客户手中。 在快递业务站中,有一些常见的设施和工作流程。首先,快递业务站通常会有专门的收件台和寄件台,顾客可以在这里将需要寄递的包裹交给快递。在收件台,工作人会核对包裹的信息,并为包裹贴上相应的快递单号。之后,包裹会被送到拣区进行类和拣。 在拣区,快递会根据区域、地址等将包裹到不同的线路上,以便在后续的派送过程中能够高效地送达给客户。拣完成后,包裹就会放置在特定的区域等待派送。 快递业务站还配备了专门的派送车辆和派送人。派送人会将包裹按照线路进行装车,并根据派送路线逐一派送给客户。派送在派送过程中需要及时更新包裹的状态,并与客户进行沟通,确保包裹能够准时送达。 快递业务站在快递业务中扮演着重要的角色。它为客户提供了方便快捷的快递服务,同时也要求工作人高效完成包裹的收发工作。只有快递业务站在装备和流程上不断优化和提升,才能更好地满足快递业务的需求,为客户提供更好的服务体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值