如何利用AI刷题基础篇3——高效刷题|豆包MarsCode AI刷题

56 阅读4分钟

本文专注于记录我如何使用AI完成算法刷题练习,以此来分享如何高效利用AI刷题。


#38补给站最优花费问题

问题描述

小明想从A徒步到B,总路程需要M天,路程中为了确保安全,小明每天需要消耗1份食物。
在起点及路程当中,零星分布着N个补给站,可以补充食物,不同补给站的食物价格可能不同。
请问小明若要安全完成徒步,最少需要花费多少钱呢?

输入格式

第一行为两个正整数MN,代表总路程M天,补给站个数N
接下来N行,每行有两个非负整数AB代表一个补给站,表示第A天经过该补给站,每份食物的价格为B元。
A是从0开始严格递增的,即起点一定有补给站,补给站是按位置顺序给出的,且同一个位置最多有一个补给站。

输出格式

输出一个整数,表示最少花费的金额

输入样例

5 4  
0 2  
1 3  
2 1  
3 2  

输出样例

7

说明:在第0天买2份食物,在第2天买3份食物,共花费7元

数据范围

  • 30%的数据,N <= M <= 100, 0 <= A < M, 0 <= B <= 1000
  • 80%的数据,N <= M <= 10000, 0 <= A < M, 0 <= B <= 1000
  • 100%的数据,N <= M <= 1000000, 0 <= A < M, 0 <= B <= 1000

思路

明确输入,输出和处理。

输入

  1. M:总路程的天数,表示小明需要徒步的天数。
  2. N:补给站的个数。
  3. 补给站数组:一个二维数组 p,其中每个元素是一个长度为2的数组 [A, B],表示在第 A 天有一个补给站,每份食物的价格为 B 元。

输出

  1. 最少花费的金额:一个整数,表示小明完成徒步所需的最少花费。

处理

  1. 设计一个数据结构存储进行存储。
  2. 设计一个算法遍历补给站,该算法时间复杂度要尽可能低,满足数据量在百万内的需求。

算法设计

读完题目,可以发现用贪心算法来解决,目标是通过最少花费确保每天有足够的食物完成旅程。

  • 关键点:每天必须有食物才能继续前进,因此需要在路途中每经过一个补给站时,决定购买多少食物。

  • 贪心策略

    • 尽可能选择食物价格最低的补给站购买。
    • 考虑当前库存是否足够支持到下一个补给站,若不足,则在当前补给站补充。
    • 避免携带过多食物以减少花费。
  • 算法步骤

    • 初始化变量:当前库存current_food为0,总花费cost为0。
    • 遍历补给站数据,计算到下一个补给站所需的食物量。
    • 如果库存不足,补充所需食物并更新花费。
    • 遍历完成后确保到达终点,若终点还有天数未覆盖,则补充足够的食物。

代码实现

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int solution(int m, int n, vector<vector<int>> p) {
    int current_food = 0; // 当前库存
    int cost = 0;         // 总花费
    int current_day = 0;  // 当前天数

    // 在补给站后增加一个虚拟终点站
    p.push_back({m, 0});

    // 优先队列用于存储 {价格, 可购买最大数量}
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;

    for (const auto &station : p) {
        int day = station[0];
        int price = station[1];

        // 需要到达该补给站需要的食物量
        int days_to_next = day - current_day;

        // 消耗当前库存
        while (current_food < days_to_next) {
            if (pq.empty()) return -1; // 无法补充足够食物,无法完成

            // 贪心选择当前最低价格
            auto [min_price, available_food] = pq.top();
            pq.pop();

            int needed = days_to_next - current_food;
            int buy = min(needed, available_food);
            cost += buy * min_price;
            current_food += buy;

            // 如果还有剩余的食物,把剩余数量放回队列
            if (available_food > buy) {
                pq.push({min_price, available_food - buy});
            }
        }

        // 更新库存和天数
        current_food -= days_to_next;
        current_day = day;

        // 将当前补给站食物加入优先队列
        if (price > 0) {
            pq.push({price, m - day}); // 假设可以购买足够到终点的数量
        }
    }

    return cost;
}

int main() {
    // 测试样例
    cout << solution(5, 4, {{0, 2}, {1, 3}, {2, 1}, {3, 2}}) << endl; // 输出 7
    return 0;
}

代码说明

  1. 优先队列:使用priority_queue存储当前可选的食物价格及库存,确保每次选择最低价格的食物。

  2. 库存更新:在每次到达补给站前计算需要补充的食物量,利用贪心策略从最低价优先购买。

  3. 特殊情况:如果无法满足所需食物量,直接返回-1

时间复杂度

  • 遍历补给站:O(N)
  • 优先队列操作:每次插入或删除操作为O(log⁡N)
  • 总复杂度约为:O(Nlog⁡N)

空间复杂度

  • 主要为优先队列的存储:O(N)