贪心入门 ————2395 - 部分背包问题
- 2395 - 部分背包问题
- 题目描述
- 输入
- 输出
- 样例
- 问题分析
- 贪心算法思路
- 代码实现
- 总结
2395 - 部分背包问题
题目描述
阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N (N < 100)堆金币,第i堆金币的总重量和总价值分别是mi,vi (l < mi, ui < 100).
阿里巴巴有一个承重量为 T(T< 1000)的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。
所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。
请问阿里巴巴最多可以拿走多少价值的金币?
输入
输入 第一行两个整数 N , T 。 接下来 N 行,每行两个整数 m i , v i 。
输出
一个实数表示答案,输出两位小数。
样例
- 输出:
4 50
10 60
20 100
30 120
15 45
- 输出:
240.00
问题分析
-
单位价值:60/10=6,100/20=5,120/30=4。
-
优先装单位价值最高的金币堆:
-
全部装入第1堆(重量10,价值60)。
-
全部装入第2堆(重量20,价值100)。
-
剩余承重 50-10-20=20,装入 20/30 的第3堆(价值 120*(20/30)=80)。
-
-
总价值:60 + 100 + 80 = 240。
贪心算法思路
-
计算单位价值:对每堆金币,计算 vi / mi(每单位重量的价值)。
-
排序:按单位价值 从高到低 排序。
-
装入背包:
-
优先装入单位价值高的金币堆。
-
如果当前堆可以完全装入(mi ≤ 剩余承重),则全部装入。
-
否则装入部分(剩余承重 / mi * vi),并结束。
-
代码实现
#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
using namespace std;struct Coin {int weight, value;double unit; // 单位价值
};bool compare(Coin a, Coin b) {return a.unit > b.unit; // 按单位价值降序排序
}int main() {int N, T;cin >> N >> T;vector<Coin> coins(N);for (int i = 0; i < N; i++) {cin >> coins[i].weight >> coins[i].value;coins[i].unit = (double)coins[i].value / coins[i].weight;}sort(coins.begin(), coins.end(), compare); // 排序double max_value = 0.0;int remaining = T; // 剩余承重for (int i = 0; i < N && remaining > 0; i++) {if (coins[i].weight <= remaining) {// 全部装入max_value += coins[i].value;remaining -= coins[i].weight;} else {// 装入部分max_value += coins[i].unit * remaining;remaining = 0;}}cout << fixed << setprecision(2) << max_value << endl;return 0;
}
总结
1.结构体定义:Coin 存储金币堆的重量、价值和单位价值。2.排序:按 unit 降序排列,优先处理高单位价值的金币。3.贪心选择:- 如果当前堆能完整装入,直接加总价值。- 否则装入部分,比例计算为 剩余承重 * unit。4.输出:保留两位小数。