字节青训-徒步旅行中的补给问题、超市里的货物架调整、观光景点组合得分问题

一、徒步旅行中的补给问题

问题描述

小明想从A徒步到B,总路程需要N天,路程中为了确保安全,小明每天需要消耗1份食物。
从起点开始,小明每天都能遇到一个补给站,可以补充食物,不同补给站的食物价格可能不同。
小明最多能同时携带K份食物,请问小明若要安全完成徒步,最少要花多少钱?

输入格式

第一行为两个正整数NK,代表总路程N天,最大负重K
第二行为N个正整数,分别代表从第0天到第N-1天,每一个补给站的食物价格。

输出格式

输出一个正整数,代表最少花费金额。

输入样例

5 2  
1 2 3 3 2

输出样例

9

说明:第0天买2份食物,花费2元;第一天买1份食物,花费2元;第三天买一份食物,花费3元;第四天买1份食物,花费2元;共花费9元。

数据范围

  • 30%的数据,N <= 100K <= N0 <= B <= 100
  • 80%的数据,N <= 10000, K <= 100, 0 <= B <= 100
  • 100%的数据,N <= 1000000, K <= N0 <= B <= 100

 解题思路:

解题思路

  1. 问题理解

    • 小R每天需要消耗1份食物,且每天经过的补给站食物价格不同。
    • 小R最多只能携带K份食物。
    • 目标是找到在N天内完成旅行所需的最小花费。
  2. 数据结构选择

    • 使用动态规划(DP)来解决这个问题。
    • 定义一个二维数组dp[i][l],表示在第i天结束时,携带l份食物的最小花费。
  3. 算法步骤

    • 初始化dp[0][0] = 0,表示在第0天结束时,携带0份食物的花费为0。
    • 状态转移
      • 对于每一天i,我们尝试从之前的某一天j转移过来。
      • 计算在第i天购买食物的花费,并更新dp[i][l]
    • 返回结果:最终返回dp[n][0],即在第n天结束时,携带0份食物的最小花费。

具体步骤

  1. 初始化DP数组

    • dp[0][0] = 0,其他dp[0][l]l > 0)为无穷大。
  2. 状态转移方程

    • 对于每一天i,遍历所有可能的食物携带量l(从0到K)。
    • 对于每一个l,再遍历前一天的所有可能的食物携带量j(从0到K)。
    • 如果l - j + 1在合理范围内(即0 <= l - j + 1 <= K),则更新dp[i][l]
  3. 返回结果

    • 最终返回dp[n][0],即在第n天结束时,携带0份食物的最小花费。

最终代码:

def solution(n, k, data):
    dp = [[float('inf')] * (k + 1) for _ in range(n + 1)]
    dp[0][0] = 0
    
    for i in range(1, n + 1):
        for l in range(k):
            for j in range(k):
                if l - j + 1 >= 0 and l - j + 1 <= k:
                    dp[i][l] = min(dp[i][l], dp[i - 1][j] + (l - j + 1) * data[i - 1])
    # print(dp)
    return dp[n][0]

if __name__ == "__main__":
    print(solution(5, 2, [1, 2, 3, 3, 2]) == 9)
    print(solution(6, 3, [4, 1, 5, 2, 1, 3]) == 9)
    print(solution(4, 1, [3, 2, 4, 1]) == 10)

运行结果:

二、超市里的货物架调整 

问题描述

在一个超市里,有一个包含 nn 个格子的货物架,每个格子中放有一种商品,商品用小写字母 a 到 z 表示。当顾客进入超市时,他们会依次从第一个格子查找到第 nn 个格子,寻找自己想要购买的商品。如果在某个格子中找到该商品,顾客就会购买它并离开;如果中途遇到一个空格子,或查找完所有格子还没有找到想要的商品,顾客也会离开。

作为超市管理员,你可以在顾客到来之前重新调整商品的顺序,以便尽可能多地出售商品。当第一个顾客进入后,商品位置不能再调整。你需要计算在最优调整下,最多可以卖出多少件商品。输入变量说明:

  • n:货物架的格子数
  • m:顾客想要购买的商品种类数
  • s:货物架上商品的初始顺序
  • c:顾客想要购买的商品种类

测试样例

样例1:

输入:n = 3 ,m = 4 ,s = "abc" ,c = "abcd"
输出:3

样例2:

输入:n = 4 ,m = 2 ,s = "abbc" ,c = "bb"
输出:2

样例3:

输入:n = 5 ,m = 4 ,s = "bcdea" ,c = "abcd"
输出:4

 解题思路:

问题理解

你需要在顾客到来之前重新调整商品的顺序,以便尽可能多地出售商品。每个顾客只会购买他们想要的商品中的一种,并且一旦找到就会离开。因此,我们的目标是通过重新排列商品,使得尽可能多的顾客能够找到他们想要的商品。

数据结构选择

  1. 商品频率统计:首先,我们需要统计货架上每种商品的数量,以及顾客想要购买的每种商品的数量。
  2. 商品匹配:然后,我们需要计算在当前货架上,最多可以满足多少种顾客的需求。

算法步骤

  1. 统计商品频率

    • 遍历货架上的商品,统计每种商品的数量。
    • 遍历顾客想要的商品,统计每种商品的需求数量。
  2. 计算最大匹配

    • 对于每种顾客想要的商品,计算货架上该商品的数量与顾客需求数量的最小值。
    • 累加这些最小值,得到最多可以满足的顾客数量。

关键点

  • 商品的顺序调整:虽然题目允许我们调整商品的顺序,但实际上我们只需要统计商品的数量,而不需要实际调整顺序。
  • 商品的匹配:我们只需要计算每种商品的供需匹配情况,而不需要实际模拟顾客的购买过程。

最终代码: 

#include <bits/stdc++.h>

using namespace std;

int solution(int n, int m, string s, string c) {
    map<char , int> ps , pc;
    for(auto it : s)
        ps[it] ++;

    for(auto it : c)
        pc[it] ++;

    int cnt = 0;
    for(auto [k , v] : pc)
        cnt += min(ps[k] , v);

    return cnt;
}

int main() {
    cout << (solution(3, 4, "abc", "abcd") == 3) << endl;
    cout << (solution(4, 2, "abbc", "bb") == 2) << endl;
    cout << (solution(5, 4, "bcdea", "abcd") == 4) << endl;
    return 0;
}

运行结果:

三、观光景点组合得分问题

问题描述

小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values 中,其中 values[i] 表示第 i 个观光景点的评分。同时,景点之间的距离由它们的下标差 j - i 表示。

一对景点 (i < j) 的观光组合得分为 values[i] + values[j] + i - j,也就是两者评分之和减去它们之间的距离。

小R想知道,在哪种情况下能够获得观光景点组合的最高得分。


测试样例

样例1:

输入:values = [8, 3, 5, 5, 6]
输出:11

样例2:

输入:values = [10, 4, 8, 7]
输出:16

样例3:

输入:values = [1, 2, 3, 4, 5]
输出:8

 解题思路:

问题理解

我们需要找到一对景点 (i, j) 使得 values[i] + values[j] + i - j 的值最大,其中 i < j

数据结构选择

我们可以使用一个变量来记录当前的最大得分,并在遍历数组时更新这个变量。

算法步骤

  1. 初始化

    • 初始化一个变量 maxScore 来记录当前的最大得分,初始值为 0。
    • 初始化一个变量 maxValue 来记录当前的最大 values[i] + i,初始值为 values[0] + 0
  2. 遍历数组

    • 从第二个元素开始遍历数组。
    • 对于每个元素 values[j],计算当前的得分 values[i] + values[j] + i - j,其中 i 是之前遍历过的元素中 values[i] + i 最大的那个。
    • 更新 maxScore 为当前得分和 maxScore 中的较大值。
    • 更新 maxValue 为 values[j] + j 和 maxValue 中的较大值。
  3. 返回结果

    • 遍历结束后,maxScore 即为所求的最大得分。

最终代码:

#include <bits/stdc++.h>

using namespace std;

int solution(vector<int> values) {
    if(values.size() == 1) return 0;
    int maxv = 0 , res = 0;

    for(int i = 0 ; i < values.size() ; i ++)
    {
        res = max(res , values[i] - i + maxv);
        maxv = max(maxv , values[i] + i);
    }
    return res; // Placeholder return
}

int main() {
    cout << (solution({8, 3, 5, 5, 6}) == 11) << endl;
    cout << (solution({10, 4, 8, 7}) == 16) << endl;
    cout << (solution({1, 2, 3, 4, 5}) == 8) << endl;
    return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

像污秽一样

谢谢谢谢谢谢谢谢谢谢谢谢

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

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

打赏作者

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

抵扣说明:

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

余额充值