【贪心】P2240 部分背包问题

125 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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;
 }