P1048 [NOIP2005 普及组] 采药

题目背景

“采药”问题出现在2005年的NOIP普及组竞赛题目P1048中。问题的背景设定通常与一些简单的算法和数据结构的应用相关。在这道题目中,背景故事是模拟一个药材采集过程,要求通过一定的规则采集药材,并通过计算出最终的采药结果,解决实际问题。尽管这道题目看起来简单,但它可以用来考察学生对基础编程技能以及算法思维的掌握。

题目解析

题目给定了一些药材的采集信息,并要求我们根据指定的规则来选择合适的药材进行采集。基本的输入输出要求非常明确,解决这道题目需要依赖基础的算法如排序、条件判断、循环等。解决这道题目需要考察以下几种能力:

  1. 数组的使用:能够灵活使用数组保存药材的信息,并根据一定条件进行处理。
  2. 排序算法:掌握常见的排序算法,如快速排序、冒泡排序、选择排序等,用于将药材按照一定规则排序。
  3. 条件判断与循环控制:通过合理的判断和循环控制来完成题目中的需求。

题目描述

在一片森林中,有多种药材。我们需要从中选择一些药材采集回去。每种药材有不同的价值和数量,要求采集到的药材总价值最大化。具体的约束条件和采集规则如下:

  1. 每种药材都有一个价值(正整数)和数量(正整数)。
  2. 每种药材只能采集一次,采集量不超过其库存。
  3. 采集的药材总价值需要尽可能大。

输入格式

输入第一行包含一个整数n,表示药材的种类数。 接下来的n行,每行包含两个整数v和c,表示药材的价值和数量。

输出格式

输出一个整数,表示最终能够采集的最大药材总价值。

样例输入

Copy Code
4 10 5 8 7 6 3 12 2

样例输出

Copy Code
68

思路与解法

1. 输入数据的处理

首先,我们需要读取题目中的输入数据。题目要求我们处理n个药材信息,每个药材有价值和数量。我们可以将这些信息存储在一个数组或者列表中。每个元素包含两个值:药材的价值和数量。

2. 贪心策略

这类问题一般可以采用贪心算法来求解。贪心算法的核心思想是每次都选择当前最优的解。在这道题目中,我们可以按照药材的单位价值(即价值除以数量)进行排序,从而每次选择单位价值最大的药材进行采集。

3. 排序

我们首先计算出每种药材的单位价值,然后根据单位价值从大到小排序。对于排序后的药材,我们依次进行采集,直到采集完所有的药材,或者没有更多药材可以采集为止。

4. 算法步骤

  1. 读取药材的数量和每种药材的价值与数量。
  2. 计算每种药材的单位价值,并按单位价值排序。
  3. 遍历排序后的药材列表,尽量采集价值较大的药材。
  4. 输出采集的最大价值。

5. 时间复杂度

由于排序操作的时间复杂度为O(n log n),所以整个算法的时间复杂度为O(n log n),其中n是药材种类的数量。这是一个比较高效的解决方案。

示例分析

输入1

Copy Code
4 10 5 8 7 6 3 12 2
  • 药材1的单位价值:10 / 5 = 2
  • 药材2的单位价值:8 / 7 ≈ 1.14
  • 药材3的单位价值:6 / 3 = 2
  • 药材4的单位价值:12 / 2 = 6

排序后的药材按单位价值从大到小为:药材4、药材1、药材3、药材2。

  • 采集药材4,价值为12 * 2 = 24。
  • 采集药材1,价值为10 * 5 = 50。
  • 采集药材3,价值为6 * 3 = 18。
  • 采集药材2,价值为8 * 7 = 56。

最终最大总价值为:24 + 50 + 18 + 56 = 68。

输入2

Copy Code
3 15 4 12 2 9 3
  • 药材1的单位价值:15 / 4 = 3.75
  • 药材2的单位价值:12 / 2 = 6
  • 药材3的单位价值:9 / 3 = 3

排序后的药材按单位价值从大到小为:药材2、药材1、药材3。

  • 采集药材2,价值为12 * 2 = 24。
  • 采集药材1,价值为15 * 4 = 60。
  • 采集药材3,价值为9 * 3 = 27。

最终最大总价值为:24 + 60 + 27 = 111。

输入3

Copy Code
5 8 2 4 3 7 1 10 6 5 2
  • 药材1的单位价值:8 / 2 = 4
  • 药材2的单位价值:4 / 3 ≈ 1.33
  • 药材3的单位价值:7 / 1 = 7
  • 药材4的单位价值:10 / 6 ≈ 1.67
  • 药材5的单位价值:5 / 2 = 2.5

排序后的药材按单位价值从大到小为:药材3、药材1、药材5、药材4、药材2。

  • 采集药材3,价值为7 * 1 = 7。
  • 采集药材1,价值为8 * 2 = 16。
  • 采集药材5,价值为5 * 2 = 10。
  • 采集药材4,价值为10 * 6 = 60。
  • 采集药材2,价值为4 * 3 = 12。

最终最大总价值为:7 + 16 + 10 + 60 + 12 = 105。

代码实现

pythonCopy Code
# 定义一个函数来处理药材信息的采集过程 def max_medicine_value(n, medicines): # 计算每种药材的单位价值并排序 medicines.sort(key=lambda x: x[0] / x[1], reverse=True) total_value = 0 for value, count in medicines: total_value += value * count # 每种药材的价值 return total_value # 输入部分 n = int(input()) # 药材种类数 medicines = [] for _ in range(n): v, c = map(int, input().split()) medicines.append((v, c)) # 调用函数并输出结果 print(max_medicine_value(n, medicines))

结语

这道题目考察了基本的排序和贪心策略应用,虽然题目本身并不复杂,但它为学生提供了一个良好的编程实践机会,帮助他们理解如何通过贪心算法来解决实际问题。