持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
【贪心】P2240 部分背包问题
题目描述
阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N(N \le 100) 堆金币,第 i 堆金币的总重量和总价值分别是 m_i,v_i(1\le m_i,v_i \le 100)。阿里巴巴有一个承重量为 T(T \le 1000) 的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价值的金币?
输入格式
第一行两个整数 N,T。
接下来 N 行,每行两个整数 m_i,v_i。
输出格式
一个实数表示答案,输出两位小数
样例 #1
样例输入 #1
4 50
10 60
20 100
30 120
15 45
样例输出 #1
240.00
解题思路
所有金币都可以分开,也就是说只要按照性价比最高的取一定得到的价值最大。
性价比就是这堆金币的价值除以重量。
只需要把这n堆金币按性价比排序就行了。
然后依次遍历,如果背包中剩余可以拿的重量大于等于这堆金币的重量,就全拿,否则直接装满。
直接装满这里注意一下整型转浮点的细节就好了。
使用tuple代替结构体,可以使代码更加简洁
Code
#include<bits/stdc++.h>
using namespace std;
using T = tuple<int,int,double>;
int main() {
int n, V;
cin >> n >> V;
vector<T> v(n);
for(auto& [m, v, r] : v) {
cin >> m >> v;
r = v * 1.0 / m;
}
sort(v.begin(), v.end(), [&](const auto& x, const auto& y){
return get<2>(x) > get<2>(y);
});
double ans = 0.0;
for(auto& [m, v, r] : v) {
if(V >= m) {
ans += v;
V -= m;
}
else {
ans += r * V;
V = 0;
break;
}
}
printf("%.2f\n", ans);
return 0;
}