洛谷P5706 【深基2.例8】再分肥宅水__C++描述

题目描述

现在有 t 毫升肥宅快乐水,要均分给 n 名同学。每名同学需要 2个杯子。现在想知道每名同学可以获得多少毫升饮料(严格精确到小数点后 3 位),以及一共需要多少个杯子。
输入一个实数 t 和一个整数n,使用空格隔开。输出两个数字表示答案,使用换行隔开。
0≤t≤10000且不超过3位小数,10001≤n≤1000

输入格式

输出格式

输入输出样例

输入
500.0 3
输出
166.667
6

思路

题意比较明确,要注意的是输出格式的控制,c语言的print()函数比较好用。

代码

#include<iostream>
#include<cstring>
#include<string>
#include<iomanip>
#include<cstdio>
using namespace std;
typedef long long ll;
int main()
{
	double a, b;
	cin >> a >> b;
	printf("%.3lf\n" , a / b);
	cout << 2 * b << endl;
	return 0;
}
<think>我们正在处理LGP2240【12.1】部分背包问题。这是一个经典的贪心算法问题,通常出现在算法学习教程中。 问题描述:有n堆金币,第i堆金币的总重量和总价值分别是m_i和v_i。现在有一个背包,它能装的最大重量为T。每堆金币可以被任意分割,分割后的价值和重量按比计算。求背包中最多能装多少价值的金币? 贪心策略:按照单位重量的价值(即v_i/m_i)从大到小排序,然后依次选取,直到背包装满。 步骤: 1. 计算每堆金币的单位价值:v_i/m_i。 2. 按单位价值从高到低排序。 3. 依次将单位价值高的金币堆放入背包,如果该堆金币全部放入背包不会超重,则全部放入;否则,只取部分(取背包剩余重量的部分)即可。 代码实现(使用C++,因为题目来源可能是,且系列通常使用C++): 注意:由于是部分背包,我们可以采用结构体或pair来存储每堆金币的重量、价值以及单位价值。 伪代码: 1. 输入:n(金币堆数)和T(背包容量) 2. 输入n堆金币,每堆的重量m_i和价值v_i 3. 计算每堆的单位价值 = v_i / m_i 4. 按照单位价值降序排序 5. 初始化当前背包已装重量为0,总价值为0 6. 遍历排序后的金币堆: if (当前堆的重量 <= 剩余背包容量) { 全部装入:总价值加上这堆金币的价值,剩余背包容量减去这堆的重量 } else { 只装入剩余背包容量那么多:总价值加上 (剩余背包容量 * 单位价值),然后剩余背包容量变为0,退出循环 } 下面给出C++代码实现: ```cpp #include <iostream> #include <algorithm> #include <iomanip> using namespace std; struct Coin { double m, v; // m:重量, v:价值 double unit; // 单位价值 }; bool cmp(Coin a, Coin b) { return a.unit > b.unit; } int main() { int n; double T; cin >> n >> T; Coin coins[105]; // 题目中n<=100,所以数组大小设为105 for (int i = 0; i < n; i++) { cin >> coins[i].m >> coins[i].v; coins[i].unit = coins[i].v / coins[i].m; } sort(coins, coins + n, cmp); double totalValue = 0.0; double remaining = T; // 剩余背包容量 for (int i = 0; i < n; i++) { if (remaining <= 0) break; if (coins[i].m <= remaining) { // 全部装入 totalValue += coins[i].v; remaining -= coins[i].m; } else { // 只取部分 totalValue += coins[i].unit * remaining; remaining = 0; break; // 背包已满,可以退出 } } cout << fixed << setprecision(2) << totalValue << endl; return 0; } ``` 注意:输出要求保留两位小数。 问题解析: 1. 为什么贪心算法适用于部分背包问题? 因为物品可以任意分割,所以我们可以按照单位价值从高到低选取,这样能保证每一步都获取当前最优解,从而整体最优。 2. 与0-1背包问题的区别:0-1背包问题中物品不可分割,所以贪心策略(按单位价值排序)并不总是最优,但部分背包问题可以使用贪心。 引用说明:部分背包问题是贪心算法的经典应用,在许多算法教材中都有提及[^1]。 §§相关问题§§ 1. 部分背包问题与0-1背包问题的区别是什么? 2. 如果部分背包问题要求输出具体选取了哪些金币堆以及每堆选取的比,如何修改代码? 3. 贪心算法在背包问题中的应用还有哪些变体? </think>### LGP2240【12.1】部分背包问题解析及解决方案 #### 问题描述 给定 $n$ 堆金币,第 $i$ 堆总重量为 $m_i$,总价值为 $v_i$。背包最大承重 $T$。每堆金币可任意分割(按比计算价值),求背包能装载的最大价值。 本质是典型的**贪心算法**问题,与0-1背包的核心区别在于物品可分割[^1]。 #### 贪心策略 1. **核心思想**:优先选择单位价值最高的金币 计算单位价值 $\varphi_i = \frac{v_i}{m_i}$ 2. **排序规则**:按 $\varphi_i$ **降序排列**金币堆 3. **装载规则**: - 若当前金币堆重量 $\leq$ 背包剩余容量 → **全装入** - 否则取剩余容量的比部分 → **部分装入** #### 算法正确性证明 通过反证法:假设存在更优方案,则必有单位价值更低的金币被优先选取,与贪心策略矛盾[^1]。 #### 代码实现(C++) ```cpp #include <iostream> #include <algorithm> #include <iomanip> using namespace std; struct Coin { double m, v; // m:重量, v:价值 double unit; // 单位价值 }; bool cmp(Coin a, Coin b) { return a.unit > b.unit; // 按单位价值降序排序 } int main() { int n; double T; cin >> n >> T; Coin coins[105]; for (int i = 0; i < n; i++) { cin >> coins[i].m >> coins[i].v; coins[i].unit = coins[i].v / coins[i].m; } sort(coins, coins + n, cmp); double totalValue = 0.0; for (int i = 0; i < n && T > 0; i++) { if (coins[i].m <= T) { // 全装入 totalValue += coins[i].v; T -= coins[i].m; } else { // 部分装入 totalValue += T * coins[i].unit; T = 0; } } cout << fixed << setprecision(2) << totalValue; return 0; } ``` #### 复杂度分析 - 时间复杂度:$O(n \log n)$(排序主导) - 空间复杂度:$O(n)$ #### 注意事项 1. 输入输出需保留2位小数(`setprecision(2)`) 2. 金币堆数 $n \leq 100$,无需考虑大数问题 3. 边界情况:当 $T=0$ 或所有金币重量为0时直接输出0.00
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值