洛谷P1909 [NOIP2016 普及组] 买铅笔经典解法

本文介绍了一段C++代码,通过结构体定义铅笔及其数量和单价,计算并找出总价格中的最大值。程序读取用户输入,使用Ceil函数确定所需购买的完整数量,以求得最低总费用。
#include<stdio.h>
#include<math.h>
#define max(a,b) (a<b? a:b) 
struct Pencil
{
	int connum;
	int perprice;
	int totalprice;
};
int main(void)
{
	int n, i;
	struct Pencil pencil[3];
	scanf("%d", &n);
	for (i = 0; i < 3; i++)
	{
		scanf("%d%d", &(pencil[i]).connum, &(pencil[i]).perprice);
		(pencil[i]).totalprice = (ceil((double)n / (double)(pencil[i]).connum)) * (pencil[i].perprice);
	}
	printf("%d", max(max((pencil[1]).totalprice, (pencil[2]).totalprice), (pencil[0]).totalprice));
	return(0);
}
<think>我们参考NOIP 2016普及组初赛试题中的铅笔问题。 问题描述:P老师需要购n支铅笔,商店有3种包装的铅笔,每种包装有不同的铅笔数量和价格。 P老师决定只同一种包装的铅笔(即只能选择一种包装,然后购若干包),目标是满足n支铅笔的需求,并且花费最小。 输入:第一行包含一个正整数n,表示需要的铅笔数量。接下来的三行,每行用两个正整数描述一种包装的铅笔: 第一个数表示这种包装内铅笔的数量,第二个数表示这种包装的价格。 输出:一个整数,表示P老师最少需要花费的钱。 思路: 1. 对于每种包装,我们需要计算为了至少到n支铅笔所需要的最小花费。 具体方法:用n除以每包的铅笔数量,如果不能整除,则需要多一包(向上取整)。 即:包数 = (n + 每包数量 - 1) / 每包数量 (整数除法,向上取整的技巧) 然后花费 = 包数 * 每包价格 2. 对三种包装分别计算花费,然后取最小值。 注意:由于n和每包数量都是正整数,我们可以使用整数除法向上取整的方法。 代码实现步骤: - 读入n - 循环3次,每次读入一种包装的铅笔数量(设为a)和价格(设为b) 计算需要购的包数:pack = (n % a == 0) ? (n / a) : (n / a + 1); 也可以使用:pack = (n + a - 1) / a; (这是整数向上取整的常用技巧) 然后计算总花费:cost = pack * b; - 比较三种包装的花费,输出最小值。 由于有三种包装,我们可以用一个数组来存储三种包装的花费,然后取最小值,也可以边读边比较。 下面我们用C语言实现: 示例输入: 57 2 2 50 30 30 27 示例输出: 54 解释:第一种包装每包2支铅笔,价格2元,需要29包(因为57/2=28.5,向上取整29),花费58元。 第二种包装每包50支,价格30元,需要2包(57/50=1.14,向上取整2),花费60元。 第三种包装每包30支,价格27元,需要2包(57/30=1.9,向上取整2),花费54元。 所以最小花费是54元。 注意:题目中给出的n最大可能为10000,铅笔数量和价格都是正整数(不超过10000),所以计算过程不会溢出。 代码: </think>以下是使用C语言解决NOIP 2016普及组"铅笔"问题的完整代码和详细思路: ### 问题分析 给定需要购铅笔总数 $n$ 和三种铅笔包装的信息(每包数量 $a_i$ 和价格 $b_i$)。目标:选择一种包装,通过购若干包使得总铅笔数 $\geq n$,并求最小花费[^1]。 **关键点**: 1. 只选择一种包装类型 2. 购数量需满足:$\text{购包数} \times a_i \geq n$ 3. 计算每种包装的最小花费:$\text{花费} = \lceil n / a_i \rceil \times b_i$ 4. 取三种包装花费的最小值 ### C语言代码实现 ```c #include <stdio.h> #include <limits.h> int main() { int n; scanf("%d", &n); // 读取需要购铅笔总数 int min_cost = INT_MAX; // 初始化最小花费为最大整数 // 处理三种包装 for (int i = 0; i < 3; i++) { int a, b; scanf("%d %d", &a, &b); // 读取当前包装的铅笔数量和价格 // 计算所需包数(向上取整) int packs = n / a; if (n % a != 0) packs++; // 如果不能整除,增加一包 // 计算当前包装总花费 int total_cost = packs * b; // 更新最小花费 if (total_cost < min_cost) { min_cost = total_cost; } } printf("%d\n", min_cost); // 输出最小花费 return 0; } ``` ### 代码解析 1. **输入处理**: - `n` 表示需要购铅笔总数 - 循环读取三种包装的铅笔数量 `a` 和价格 `b` 2. **包数计算**: - 使用整数除法 `n / a` 计算基础包数 - 通过 `if (n % a != 0) packs++` 实现向上取整 3. **花费计算**: - 当前包装总花费 = 包数 × 单价 (`packs * b`) - 使用 `min_cost` 记录全局最小花费 4. **时间复杂度**:$O(1)$,固定处理三种包装 ### 示例测试 **输入**: ``` 57 2 2 50 30 30 27 ``` **输出**: ``` 54 ``` **计算过程**: - 包装1:需 $\lceil 57/2 \rceil = 29$ 包 → $29 \times 2 = 58$ 元 - 包装2:需 $\lceil 57/50 \rceil = 2$ 包 → $2 \times 30 = 60$ 元 - 包装3:需 $\lceil 57/30 \rceil = 2$ 包 → $2 \times 27 = 54$ 元 - 最小花费为 54 元 ### 优化技巧 1. **避免除法取整**:可直接计算 `packs = (n + a - 1) / a` 2. **边界处理**:当 $n=0$ 时花费应为 $0$(题目隐含 $n \geq 1$) ### 典型应用场景 1. 资源采购优化(批量采购成本计算) 2. 活动物资筹备(最小化预算) 3. 算法竞赛中的贪心策略训练
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值