42. 导师请吃火锅

134 阅读3分钟

题目描述

入职后,导师会请你吃饭,你选择了火锅。 火锅里会在不同时间下很多菜. 不同食材要煮不同的时间,才能变得刚好合适。 你希望吃到最多的刚好合适的菜,但你的手速不够快,用 m 代表手速,每次下手捞菜后至少要过 m 秒才能再捞(每次只能捞一个)。 那么用最合理的策略,最多能吃到多少刚好合适的菜?

输入描述

第一行两个整数 n,m,其中 n 代表往锅里下的菜的个数,m 代表手速。 (1<n,m< 1000)
接下来有 n 行,每行有两个数 x,y 代表第 x 秒下的菜过 y 秒才能变得刚好合适。
(1<x,y< 1000)。

输出描述

输出一个整数代表用最合理的策略,最多能吃到刚好合适的菜的数量。

用例

输入
3 2
1 2
2 1
3 2

输出
2

ps:
往锅里下的菜的个数3,手速2;
第1秒的时候下入菜品1,2秒后熟了;
第2秒的时候下入菜品2,1秒后熟了;
第3秒的时候下入菜品3,2秒后熟了;
第一种菜品和第二种菜品只能吃到一种,第三种菜品可以吃到;
输出 2

思路

这个算法的核心思想是贪心算法,即在每一步都做出局部最优的选择,从而希望最终得到全局最优解。在这个问题中,局部最优的选择是尽可能早地捞那些变刚好合适的菜,这样可以留出更多的时间来捞后面的菜。以下是详细的解释:

为什么这样可以吃到最多的菜?

  1. 按变刚好合适的时间排序

    • 我们首先计算每个菜变刚好合适的时间 x + y,然后按 x+y 时间升序排序。这样做是为了确保我们总是先考虑最早变刚好合适的菜。
  2. 尽可能早地捞菜

    • 通过按 x + y 时间排序,我们可以确保每次捞菜时,选择的是当前时间之前最早变刚好合适的菜。这样可以最大化我们捞菜的机会,因为如果我们错过了早期的菜,后面的时间可能会被浪费。
  3. 手速限制

    • 每次捞菜后,手速 m 会限制我们再次捞菜的时间。因此,我们需要确保在满足手速限制的前提下,尽可能多地捞到菜。
  4. 维护上一次捞菜的时间

    • 我们用一个变量 last_time 来记录上一次捞菜的时间。每次捞菜后,更新 last_time 为当前菜的 x + y 时间。这样可以确保我们不会违反手速限制。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main()
{
    int n, m;
    cin >> n >> m;
    vector<int> food(n);
    for (int i = 0; i < n; i++)
    {
        int x, y;
        cin >> x >> y;
        food[i] = x + y;
    }

    sort(food.begin(), food.end());

    // 第一筷子肯定要吃到
    int last_time = food[0];
    int count = 1;

    for (int i = 1; i < n; i++)
    {
        if (last_time + m <= food[i])
        {
            count++;
            last_time = food[i];
        }
    }

    cout << count << endl;
    return 0;
}