华为OD机试真题---云短信平台优惠活动

华为OD机试真题中的“云短信平台优惠活动”题目描述如下:

一、题目描述

某云短信厂商为庆祝国庆,推出充值优惠活动。现在给出客户预算和优惠售价序列,要求计算最多可获得的短信总条数。

二、输入描述

  • 第一行客户预算M,其中0 ≤ M ≤ 10^6。
  • 第二行给出售价表,P1, P2,…, Pn,其中1 ≤ n ≤ 100。Pi表示充值i元获得的短信条数,1 ≤ Pi ≤ 1000。

三、输出描述

  • 输出最多获得的短信总条数。

四、示例

示例1

  • 输入:
6 
10 20 30 40 60
  • 输出:70
  • 说明:分两次充值最优,1元和5元各充一次,总条数为10 + 60 = 70。

示例2

  • 输入:
18 
1 2 30 40 60 84 70 80 90 150
  • 输出:
252

五、解题思路

这个问题是一个经典的完全背包问题,其中每个充值方案(即物品)可以多次使用。我们需要在给定预算下,最大化可获得的短信条数。可以通过动态规划算法来解决这个问题。

  1. 定义一个数组dp,其中dp[j]表示在预算为j时最多能获得的短信条数。
  2. 初始化dp数组,dp[0] = 0,表示在预算为0时无法获得任何短信。
  3. 遍历每个充值方案,对于每个充值方案pi(表示充值i元获得的短信条数),更新dp数组。对于每个可能的预算j(j从i到M),如果j >= i,则尝试使用当前充值方案pi来更新dp[j],即dp[j] = max(dp[j], dp[j - i] + pi)。
  4. 遍历完成后,dp[M]即为最多能获得的短信条数。

六、代码实现



import java.util.Scanner;

public class CloudSMSDiscount {
        /*
         * 主函数
         * 读取用户输入的预算和手机售价表,计算并输出在给定预算下最多能获得的短信总条数
         * @param args 命令行参数
         */
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
    
            // 读取客户预算
            int M = scanner.nextInt();
            scanner.nextLine(); // 消耗掉换行符
    
            // 读取售价表
            String[] n = scanner.nextLine().split(" ");
    
            // 将售价表字符串转换为整数数组
            int[] prices = new int[n.length];
            for (int i = 0; i < n.length; i++) {
                prices[i] = Integer.parseInt(n[i]);
            }
    
            // 动态规划数组,dp[j]表示在预算为j时最多能获得的短信条数
            int[] dp = new int[M + 1];
    
            // 遍历每个充值方案
            for (int i = 0; i < n.length; i++) {
                int cost = i + 1; // 售价表中的索引从0开始,但充值金额从1开始
                int smsCount = prices[i];
    
                // 更新dp数组
                for (int j = cost; j <= M; j++) {
                    dp[j] = Math.max(dp[j], dp[j - cost] + smsCount);
                }
            }
    
            // 输出最多获得的短信总条数
            System.out.println(dp[M]);
    
            scanner.close();
        }
    }


七、注意事项

  1. 输入处理

    • 读取客户预算M
    • 读取售价表长度n,然后读取n个售价值存入数组prices
  2. 动态规划数组

    • dp数组的长度为M + 1,因为预算M是一个上限值,数组索引从0到M。
    • 初始化时,dp数组的所有元素默认为0(Java中int数组默认初始化为0)。
  3. 状态转移

    • 遍历每个充值方案,用cost表示充值金额(从1开始,因为售价表中的索引从0开始)。
    • smsCount表示充值后获得的短信条数。
    • 更新dp数组时,从cost开始遍历到M,对于每个j,尝试使用当前充值方案来更新dp[j]
  4. 输出结果

    • 最后,dp[M]存储的是在预算为M时最多能获得的短信条数。

八、测试用例解析

代码解析
  1. 主函数(main方法)

    • 初始化Scanner对象以读取用户输入。
    • 读取客户预算M
    • 消耗掉输入缓冲区中的换行符,避免影响后续nextLine()的读取。
    • 读取售价表,使用nextLine()获取一行输入,然后使用split(" ")将其拆分为字符串数组。
    • 将字符串数组转换为整数数组prices
    • 初始化动态规划数组dp,长度为M + 1,所有元素默认初始化为0。
    • 遍历每个充值方案,更新dp数组以记录在给定预算下最多能获得的短信条数。
    • 输出dp[M],即在预算为M时最多能获得的短信条数。
    • 关闭Scanner对象。
  2. 动态规划部分

    • 对于每个充值方案(由prices数组中的值表示),将其索引i加1作为充值金额cost(因为售价表中的索引从0开始,但充值金额从1开始)。
    • smsCount表示充值cost元后获得的短信条数。
    • 对于每个可能的预算j(从costM),尝试使用当前充值方案来更新dp[j]。如果充值cost元后获得的短信条数加上剩余预算j - cost时能获得的最多短信条数大于当前dp[j]的值,则更新dp[j]
运行示例解析

输入:

6
10 20 30 40 60

执行流程:

  1. 读取预算M = 6
  2. 读取售价表,转换为整数数组prices = [10, 20, 30, 40, 60]
  3. 初始化动态规划数组dp,长度为7(M + 1),初始值为[0, 0, 0, 0, 0, 0, 0]
  4. 遍历每个充值方案:
    • i = 0时,cost = 1smsCount = 10。由于cost = 1小于M,更新dp数组:
      • dp[1] = Math.max(dp[1], dp[0] + 10) = 10
      • dp[2]dp[6]保持不变,因为cost = 1不足以覆盖这些预算。
    • i = 1时,cost = 2smsCount = 20。更新dp数组:
      • dp[2] = Math.max(dp[2], dp[0] + 20) = 20
      • dp[3] = Math.max(dp[3], dp[1] + 20) = 30(因为dp[1]已被更新为10)
      • dp[4]dp[6]保持不变。
    • 类似地,继续遍历i = 2, 3, 4,更新dp数组:
      • i = 2时,cost = 3smsCount = 30,更新dp[3]dp[6]
      • i = 3时,cost = 4smsCount = 40,更新dp[4]dp[6]
      • i = 4时,cost = 5smsCount = 60,仅更新dp[6],因为dp[5]在之前的迭代中已被更新。
  5. 最终,dp数组变为[0, 10, 20, 30, 40, 60, 70]
  6. 输出dp[6] = 70,即在预算为6时最多能获得的短信条数。

因此,对于输入6 10 20 30 40 60,程序输出70,这是正确的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值