2024-12-26 - 第 43 篇
洛谷贪心算法题单 - 贪心算法 - 学习笔记
作者(Author): 郑龙浩 / 仟濹(CSND账号名)
洛谷P1208 [USACO1.3] 混合牛奶 Mixing Milk
文章目录
- [洛谷P1208 [USACO1.3] 混合牛奶 Mixing Milk](#洛谷P1208 [USACO1.3] 混合牛奶 Mixing Milk)
题目描述
由于乳制品产业利润很低,所以降低原材料(牛奶)价格就变得十分重要。帮助 Marry 乳业找到最优的牛奶采购方案。
Marry 乳业从一些奶农手中采购牛奶,并且每一位奶农为乳制品加工企业提供的价格可能相同。此外,就像每头奶牛每天只能挤出固定数量的奶,每位奶农每天能提供的牛奶数量是一定的。每天 Marry 乳业可以从奶农手中采购到小于或者等于奶农最大产量的整数数量的牛奶。
给出 Marry 乳业每天对牛奶的需求量,还有每位奶农提供的牛奶单价和产量。计算采购足够数量的牛奶所需的最小花费。
注:每天所有奶农的总产量大于 Marry 乳业的需求量。
输入格式
第一行二个整数 n , m n,m n,m,表示需要牛奶的总量,和提供牛奶的农民个数。
接下来 m m m 行,每行两个整数 p i , a i p_i,a_i pi,ai,表示第 i i i 个农民牛奶的单价,和农民 i i i 一天最多能卖出的牛奶量。
输出格式
单独的一行包含单独的一个整数,表示 Marry 的牛奶制造公司拿到所需的牛奶所要的最小费用。
样例 #1
样例输入 #1
100 5
5 20
9 40
3 10
8 80
6 30
样例输出 #1
630
提示:
【数据范围】
对于 100 % 100\% 100% 的数据:
0 ≤ n , a i ≤ 2 × 1 0 6 0 \le n,a_i \le 2 \times 10^6 0≤n,ai≤2×106, 0 ≤ m ≤ 5000 0\le m \le 5000 0≤m≤5000, 0 ≤ p i ≤ 1000 0 \le p_i \le 1000 0≤pi≤1000
题目翻译来自 NOCOW。
USACO Training Section 1.3
思路:
因为要追求"花费最低"怎么购买牛奶,所以肯定要将单价低的排在前边。然后根据单价去购买牛奶。
排序好以后
第一次循环 :每次累加 该农民的所有的牛奶量,若遇到 牛奶总量 + 该农民所有的牛奶量 > 需要的牛奶总量 --> 则代表再继续购买该农民的所有牛奶量,就会超过所需牛奶量,显然是不能继续 + 了
但是此时会出现两种情况:
- 1.本来【购买牛奶量】== 【所需牛奶量】 此时+ 【该农民所有的牛奶量】也是 > 【所需牛奶量】,所以即使退出循环,也无需再进行购买了,因为已经足够了
- 2.本来【购买牛奶量】< 【所需牛奶量】 此时+ 【该农民所有的牛奶量】是 > 【所需牛奶量】,因为还没有买够,所以还是需要购买,"只是"不能购买【该农民全部的牛奶量】了,
而是以【该农民的 1 个单位的牛奶量】去逐个循环累加,直到 【购买牛奶量】 == 【所需牛奶量】
"当然"每次累加到牛奶总量的时候都要进行价格累加计算。第二次循环:若是情况2,会进入该循环,以【该农民 1 个单位的牛奶量】为一个单位进行累加,同时总价格 也是 以一个单位的牛奶量对应价格 进行累加
- 定义 变量结构体、输入数据
- 按照价格 由低到高 进行排序
- 进入第一次循环for --> 从最低价到最高价以【该农民的所有牛奶量】为一个单位进行累加,同时计算出购买的总价格
退出条件 : 【购买牛奶量】 + 【该农民所有的牛奶量】 > 【所需牛奶量】
退出循环的两种情况 :
- 【购买牛奶量】 == 【所需牛奶量】
- 【购买牛奶量】 < 【所需牛奶量】
- 进入第二次循环while --> 若是情况2,会进入该循环
循环条件 : 【购买牛奶量】 < 【所需牛奶量】 反之:退出条件 就是 【购买牛奶量】 == 【所需牛奶量】,因为总量累加是加一,故不会出现 > 的情况,只会有 == 的情况
循环体: 累加 【该农民 1 个单位的牛奶量】,同时累加 1 个单位的价格(而不是曾经以【该农民的所有牛奶量】为一个单位进行累加)- 打印总价格
代码:
cpp
// 洛谷P1208混合牛奶_Mixing_Milk
// 【贪心算法】
// 思路:
// 因为要追求"花费最低"怎么购买牛奶,所以肯定要将单价低的排在前边。然后根据单价去购买牛奶。排序好以后
// 第一次循环:每次累加 该农民的所有的牛奶量,若遇到 牛奶总量 + 该农民所有的牛奶量 > 需要的牛奶总量 --> 则代表再继续购买该农民的所有牛奶量,就会超过所需牛奶量,显然是不能继续 + 了
// 但是此时会出现两种情况:1. 本来【购买牛奶量】== 【所需牛奶量】 此时+ 【该农民所有的牛奶量】也是 > 【所需牛奶量】,所以即使退出循环,也无需再进行购买了,因为已经足够了
// 2. 本来【购买牛奶量】< 【所需牛奶量】 此时+ 【该农民所有的牛奶量】是 > 【所需牛奶量】,因为还没有买够,所以还是需要购买,"只是"不能购买【该农民全部的牛奶量】了,
// 而是以【该农民的 1 个单位的牛奶量】去逐个循环累加,直到 【购买牛奶量】 == 【所需牛奶量】
// 第二次循环:若是情况2,会进入该循环,以【该农民 1 个单位的牛奶量】为一个单位进行累加,同时总价格 也是 以一个单位的牛奶量对应价格 进行累加
// "当然"每次累加到牛奶总量的时候都要进行价格累加计算。
// 1. 定义变量结构体、输入数据
// 2. 按照价格 由低到高 进行排序
// 3. 进入第一次循环for --> 从最低价到最高价以【该农民的所有牛奶量】为一个单位进行累加,同时计算出购买的总价格
// 退出条件: 【购买牛奶量】 + 【该农民所有的牛奶量】 > 【所需牛奶量】
// 退出循环的两种情况:
// 1. 【购买牛奶量】 == 【所需牛奶量】
// 2. 【购买牛奶量】 < 【所需牛奶量】
// 4. 进入第二次循环while --> 若是情况2,会进入该循环
// 循环条件: 【购买牛奶量】 < 【所需牛奶量】 反之:退出条件就是 【购买牛奶量】 == 【所需牛奶量】,因为总量累加是加一,故不会出现 > 的情况,只会有 == 的情况
// 循环体: 累加 【该农民 1 个单位的牛奶量】,同时累加 1 个单位的价格(而不是曾经以【该农民的所有牛奶量】为一个单位进行累加)
// 5. 打印总价格
#include <iostream>
#include <algorithm>
using namespace std;
struct ddd{
int price; // 表示该农民的 【单价】
int num; // 表示该农民一天最多能卖出的【牛奶量】
};
// 价格低的排在前面
bool cmp( ddd a, ddd b ){
return a.price < b.price;
}
int main( void ){
int n, m; // 需要的牛奶总量,能提供牛奶的农民个数
cin >> n >> m;
ddd data[ m ];
// 输入数据
for (int i = 0; i < m; i ++ ){
cin >> data[ i ].price >> data[ i ].num; // 输入单价和数量
}
// 价格排序
sort ( data, data + m, cmp ); // 排序,将价格低的排在前边
int sum = 0, price_sum; // 计数变量 已购买牛奶的总量,目前已花的总价格
int i = 0;
for ( i = 0; i < m; i ++ ){
// 如果 牛奶总量 + 该农民所有的牛奶量 > 需要的牛奶总量 --> 退出循环,然后就不+该农民的所有的牛奶量,而是 1 个单位 1 个单位的加,直到 == 所需的牛奶总量
if ( sum + data[ i ].num > n ) break;
sum += data[ i ].num; // 总量 + 农民的总量
price_sum += data[ i ].price * data[ i ].num; // 单价 * 数量
}
// 以 1 个牛奶量的单位循环累加,直到 == 所需的牛奶总量
// 情况1: 退出循环的时候 num < n --> 不够,还需要进行累加
// 情况2: 退出循环的时候 num == n --> 够了,while循环是不会进入的,因为不符合循环条件:sum < n,只在牛奶总量不够的时候才会进行累加到总量的计算
while ( sum < n ){
price_sum += data[ i ].price;
sum ++;
}
cout << price_sum;
return 0;
}