题目来源:【深基12.例1】部分背包问题 - 洛谷
参考书目:《深入浅出程序设计竞赛(基础篇)》
解题思路:这道题是部分背包,如果金币不能完整的放入是可以分割的。题目中有若干堆金币,每堆金币有一定的重量(m
)和价值(v
),以及一个最大承重为 t
的背包。目标是通过完全或部分地拿取这些金币堆,使得背包中的金币价值最大化。代码采用贪心算法,通过按价值与重量比降序排序金币堆,然后迭代地将它们添加到背包中,直到背包装满或没有更多的金币堆可考虑。
解题步骤:
- 迭代读取每堆金币的重量和价值,并存储在数组
a
中。 - 使用
sort
函数和cmp
比较函数对金币堆进行排序。 - 迭代地将每堆金币加入背包:
- 如果当前金币堆的重量大于剩余容量,则跳出循环。
- 否则,从剩余容量中减去金币堆的重量,并将其价值加到总价值
ans
上。
- 如果因为一堆金币无法完全加入而退出循环,将该金币堆的一部分加入到
ans
中,以填满剩余容量。 - 最后,打印出总价值
ans
,保留两位小数。
#include<iostream>
#include<algorithm>using namespace std;// 定义结构体来存储每堆金币的重量和价值
struct coin {int m, v; // 金币堆的重量和价值
} a[110];// 比较函数,用于根据价值与重量的比率(性价比)进行排序
bool cmp(coin x, coin y)
{return x.v * y.m > y.v * x.m; // 比较两堆金币的性价比
}int main()
{int n, t, c, i;float ans = 0; // 初始化答案变量cin >> n >> t; // 读入金币堆数和背包容量c = t; // 背包剩余容量初始化为背包总容量// 读入每堆金币的重量和价值for (i = 0; i < n; i++){cin >> a[i].m >> a[i].v;}// 对金币堆按性价比降序排序sort(a, a + n, cmp);// 遍历金币堆,尝试将它们加入背包for (i = 0; i < n; i++){if (a[i].m > c) break; // 如果当前金币堆无法完全装入背包,则跳出循环c -= a[i].m; // 减少背包剩余容量ans += a[i].v; // 增加背包中金币的总价值}// 如果退出循环是因为一堆金币无法完全加入,则加入这堆金币的一部分if (i < n){ans += 1.0 * c / a[i].m * a[i].v; // 加入部分金币堆,按比例计算价值}// 输出最终答案,保留两位小数printf("%.2lf", ans);return 0;
}