一、徒步旅行中的补给问题
问题描述
小明想从A徒步到B,总路程需要N
天,路程中为了确保安全,小明每天需要消耗1份食物。
从起点开始,小明每天都能遇到一个补给站,可以补充食物,不同补给站的食物价格可能不同。
小明最多能同时携带K
份食物,请问小明若要安全完成徒步,最少要花多少钱?
输入格式
第一行为两个正整数N
、K
,代表总路程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 <= 100
,K <= N
,0 <= B <= 100
- 80%的数据,
N <= 10000
,K <= 100
,0 <= B <= 100
- 100%的数据,
N <= 1000000
,K <= N
,0 <= B <= 100
解题思路:
解题思路
-
问题理解:
- 小R每天需要消耗1份食物,且每天经过的补给站食物价格不同。
- 小R最多只能携带
K
份食物。 - 目标是找到在
N
天内完成旅行所需的最小花费。
-
数据结构选择:
- 使用动态规划(DP)来解决这个问题。
- 定义一个二维数组
dp[i][l]
,表示在第i
天结束时,携带l
份食物的最小花费。
-
算法步骤:
- 初始化:
dp[0][0] = 0
,表示在第0天结束时,携带0份食物的花费为0。 - 状态转移:
- 对于每一天
i
,我们尝试从之前的某一天j
转移过来。 - 计算在第
i
天购买食物的花费,并更新dp[i][l]
。
- 对于每一天
- 返回结果:最终返回
dp[n][0]
,即在第n
天结束时,携带0份食物的最小花费。
- 初始化:
具体步骤
-
初始化DP数组:
dp[0][0] = 0
,其他dp[0][l]
(l > 0
)为无穷大。
-
状态转移方程:
- 对于每一天
i
,遍历所有可能的食物携带量l
(从0到K
)。 - 对于每一个
l
,再遍历前一天的所有可能的食物携带量j
(从0到K
)。 - 如果
l - j + 1
在合理范围内(即0 <= l - j + 1 <= K
),则更新dp[i][l]
。
- 对于每一天
-
返回结果:
- 最终返回
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
解题思路:
问题理解
你需要在顾客到来之前重新调整商品的顺序,以便尽可能多地出售商品。每个顾客只会购买他们想要的商品中的一种,并且一旦找到就会离开。因此,我们的目标是通过重新排列商品,使得尽可能多的顾客能够找到他们想要的商品。
数据结构选择
- 商品频率统计:首先,我们需要统计货架上每种商品的数量,以及顾客想要购买的每种商品的数量。
- 商品匹配:然后,我们需要计算在当前货架上,最多可以满足多少种顾客的需求。
算法步骤
-
统计商品频率:
- 遍历货架上的商品,统计每种商品的数量。
- 遍历顾客想要的商品,统计每种商品的需求数量。
-
计算最大匹配:
- 对于每种顾客想要的商品,计算货架上该商品的数量与顾客需求数量的最小值。
- 累加这些最小值,得到最多可以满足的顾客数量。
关键点
- 商品的顺序调整:虽然题目允许我们调整商品的顺序,但实际上我们只需要统计商品的数量,而不需要实际调整顺序。
- 商品的匹配:我们只需要计算每种商品的供需匹配情况,而不需要实际模拟顾客的购买过程。
最终代码:
#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
。
数据结构选择
我们可以使用一个变量来记录当前的最大得分,并在遍历数组时更新这个变量。
算法步骤
-
初始化:
- 初始化一个变量
maxScore
来记录当前的最大得分,初始值为 0。 - 初始化一个变量
maxValue
来记录当前的最大values[i] + i
,初始值为values[0] + 0
。
- 初始化一个变量
-
遍历数组:
- 从第二个元素开始遍历数组。
- 对于每个元素
values[j]
,计算当前的得分values[i] + values[j] + i - j
,其中i
是之前遍历过的元素中values[i] + i
最大的那个。 - 更新
maxScore
为当前得分和maxScore
中的较大值。 - 更新
maxValue
为values[j] + j
和maxValue
中的较大值。
-
返回结果:
- 遍历结束后,
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;
}