csp信奥赛C++高频考点专项训练之贪心算法 --【部分背包问题】:部分背包问题
#### 题目描述
阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N ( N ≤ 100 ) N(N \le 100) N(N≤100) 堆金币,第 i i i 堆金币的总重量和总价值分别是 m i , v i ( 1 ≤ m i , v i ≤ 100 ) m_i,v_i(1\le m_i,v_i \le 100) mi,vi(1≤mi,vi≤100)。阿里巴巴有一个承重量为 T ( T ≤ 1000 ) T(T \le 1000) T(T≤1000) 的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价值的金币?
输入格式
第一行两个整数 N , T N,T N,T。
接下来 N N N 行,每行两个整数 m i , v i m_i,v_i mi,vi。
输出格式
一个实数表示答案,输出两位小数。
输入输出样例 1
输入 1
4 50
10 60
20 100
25 100
15 45
输出 1
240.00
思路分析
这是一个典型的部分背包问题 (也称为分数背包问题)。与 0/1 背包不同,金币可以任意分割,因此最优策略是优先选择单位价值(价值/重量)最高的金币堆,直到背包装满。
具体步骤:
- 计算每堆金币的单位价值
avg = v / m。 - 将所有金币堆按
avg降序排序。 - 遍历排序后的金币堆:
- 如果当前堆可以全部装入,则全部拿走,背包容量减少,总价值增加。
- 否则,只装入剩余容量所能容纳的部分(按比例计算价值),然后结束。
- 输出总价值,保留两位小数。
时间复杂度:排序 O(N log N),遍历 O(N),满足 N ≤ 100 的约束。
代码实现
cpp
#include<bits/stdc++.h>
using namespace std;
struct node {
double m, v, avg; // 重量、总价值、单位价值
} a[110];
bool cmp(node x, node y) {
return x.avg > y.avg; // 按单位价值降序排序
}
int main() {
int n, t; // n:堆数, t:背包容量
cin >> n >> t;
for (int i = 1; i <= n; i++) {
cin >> a[i].m >> a[i].v;
a[i].avg = a[i].v / a[i].m; // 计算单位价值
}
sort(a + 1, a + n + 1, cmp); // 贪心排序
double ans = 0; // 记录最大价值
for (int i = 1; i <= n && t > 0; i++) {
if (t >= a[i].m) { // 能全部装下
ans += a[i].v;
t -= a[i].m;
} else { // 只能装部分
ans += t * a[i].avg; // 按比例计算价值
t = 0;// 背包已满
}
}
printf("%.2lf\n", ans); // 输出两位小数
return 0;
}
功能分析
- 输入处理 :读取金币堆数
n和背包容量t,再依次读取每堆的重量m和价值v。 - 单位价值计算 :
avg = v / m,用于贪心决策。 - 排序:按单位价值从高到低排列,确保优先取"性价比"最高的金币。
- 贪心装载 :
- 若当前堆能完全装入,则全部拿走。
- 否则只取剩余容量对应的部分(重量 × 单位价值),背包随即装满。
- 输出 :使用
printf格式化输出两位小数的最大价值。
各种学习资料,助力大家一站式学习和提升!!!
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"########## 一站式掌握信奥赛知识! ##########";
cout<<"############# 冲刺信奥赛拿奖! #############";
cout<<"###### 课程购买后永久学习,不受限制! ######";
return 0;
}
【秘籍汇总】(完整csp信奥赛C++学习资料):
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转
4、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}