部分背包模板:按单位重量价值降序贪心,能装全装、装不下就切一部分。
OJ: roj
题目 ID: 1225
难度:普及-
标签:贪心排序
创建: 2026-09-30 00:28
更新: 2026-10-05 05:57
题目描述
口袋承重上限为
输入:先给测试组数
思路
每种金属单位重量价值为
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 00:28
# update_at: 2026-09-30 00:28
import sys
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
out: list[str] = []
T = next(data)
for _ in range(T):
w = next(data) # 口袋承重上限
s = next(data) # 金属种类数
metals = [] # (单位重量价值, 总重量),后面按单价从高到低取
for _ in range(s):
n_i, v_i = next(data), next(data)
metals.append((v_i / n_i, n_i))
metals.sort(reverse=True) # 贪心:单价越高越先装
value = 0.0 # 已装下的总价值
for unit, weight in metals:
taken = min(weight, w) # 这一种最多还能装多少
value += taken * unit # 价值和重量成正比
w -= taken # 剩余承重
if w == 0:
break # 装满了,后面的金属不再看
out.append(f"{value:.2f}")
print('\n'.join(out))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 05:57
* update_at: 2026-10-05 05:58
*/
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
typedef long long ll;
struct Metal {
ll w; // 该种金属的总重量
ll v; // 该种金属的总价值
double u; // 单价 = v / w
};
const int MAXS = 105;
Metal a[MAXS];
bool cmp(Metal x, Metal y) {
return x.u > y.u;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int k;
cin >> k;
while (k--) {
ll w, s;
cin >> w >> s;
for (int i = 1; i <= s; i++) {
cin >> a[i].w >> a[i].v;
a[i].u = (double)a[i].v / (double)a[i].w;
}
sort(a + 1, a + s + 1, cmp);
double ans = 0;
ll rest = w;
for (int i = 1; i <= s && rest > 0; i++) {
ll take = min(a[i].w, rest);
ans += take * a[i].u;
rest -= take;
}
cout << fixed << setprecision(2) << ans << "\n";
}
return 0;
}