题目出自官方题单算法1-5贪心题单
附链接:
P2240 【深基12.例1】部分背包问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
求助大佬的帖子:
20分萌新求助 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
解题思路
主要来源于LCY算法入门培训第2讲
根据每堆金币单位重量的价值进行排序 然后从最大价值开始填满背包库存
既然允许金币分割 那就开始贪呗(
代码实现(第一次)
祖传冒泡(因为数据组数不算太大所以冒泡排序先写着也是可以的)
#include <bits/stdc++.h>
using namespace std;
int T, n;
double ans;
//std::swap也是能用的 当时写上头了
void swap(int &a, int &b) {
int t = a;
a = b;
b = t;
}
int main() {
//输入数据组数和背包容量
cin >> T >> n;
int a[T], b[T];
//开俩数组分别来存每堆金币的重量和
for (int i = 0; i < T; i++) {
cin >> a[i] >> b[i];
}
//祖传冒泡 通过比较相邻两堆金币的价值进行 降序 排序
for (int i = 0; i < T - 1; i++) {
for (int j = i; j < T - 1; j++) {
if (double(b[j] / a[j]) < double(b[j + 1] / a[j + 1])) {
swap(a[j], a[j + 1]);
swap(b[j], b[j + 1]);
}
}
}
//金币堆现在降序排序 也就是说我们可以从顶上开始吃(
//开始扫描所有金币 如果包的容量n大于当前金币a[i]则全部收下,并且包的容量n减去当前金币的重量b[i],ans加上当前金币的价值
for (int i = 0; i < T; i++) {
if (n >= a[i]) {
n -= a[i];
ans += b[i];
} else {
ans += double(b[i] / a[i]) * n;
break;
//不加break会让程序出错
}
}
//完美收官(误)
printf("%.2lf", ans);
return 0;
}
是不是感觉看上去像模像样的?有种快要AC的错觉了是把?
不需要数据,double(b[j] / a[j]) < double(b[j + 1] / a[j + 1])
显然是错的。
double()是强制转换类型了 但是呢? b[j]/a[j]仍然是"整数除以整数" 这东西能排序 但只能排一点点
比如这东西就分辨不出3 7和3 6的价值哪个更高
在不断尝试中 我发现问题主要还是出在排序上
当时没想那么多于是我改了改排序和swap:
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
//省略其他部分
for (int i = 0; i < T - 1; i++) {
for (int j = i; j < T - 1; j++) {
double t1 = (double)b[j] / a[j];
double t2 = (double)b[j + 1] / a[j + 1];
if (t1 < t2) {
swap(a + j, a + j + 1);
swap(b + j, b + j + 1);
}
}
}
但不幸的是 这玩意仍然有问题 于是我直接开了第三个double数组直接拿来存每堆金币的价值
AC代码
#include <bits/stdc++.h>
using namespace std;
//swap改回来了
void swap(int &a, int &b) {
int t = a;
a = b;
b = t;
}
int main() {
int T, n;
double ans = 0;
cin >> T >> n;
int a[T], b[T];
//开新的数组
double c[T];
for (int i = 0; i < T; i++) {
cin >> a[i] >> b[i];
//给新的数组赋值
c[i] = double(b[i]) / double(a[i]);
}
for (int i = 0; i < T - 1; i++) {
for (int j = 0; j < T - 1; j++) {
if (c[j] < c[j + 1]) {
//三个一起换
swap(a[j], a[j + 1]);
swap(b[j], b[j + 1]);
swap(c[j], c[j + 1]);
}
}
}
for (int i = 0; i < T; i++) {
if (n >= a[i]) {
n -= a[i];
ans += b[i];
} else {
ans += double(b[i]) / double(a[i]) * n;
break;
}
}
//完美(
printf("%.2lf", ans);
return 0;
}
写完代码10分钟 改代码100分钟
如何避免出现开三个数组同时进行排序这样的惨案?(AC代码)
使用结构体就好了(笑)
#include <bits/stdc++.h>
using namespace std;
struct Gold {
int w;
int p;
double ppw;
};
//降序按照ppw(price_per_weight)排列
bool cmp(Gold a, Gold b) {
return a.ppw > b.ppw;
}
void swap(int &a, int &b) {
int t = a;
a = b;
b = t;
}
int main() {
double ans = 0;
int T, n;
scanf("%d %d", &T, &n);
struct Gold g[T];
for (int i = 0; i < T; i++) {
scanf("%d %d", &g[i].w, &g[i].p);
g[i].ppw = double(g[i].p) / double(g[i].w);
}
sort(g, g + T, cmp);
// for (int i = 0; i < T; i++) {
// cout << g[i].ppw << " ";
// }
for (int i = 0; i < T; i++) {
if (n >= g[i].w) {
n -= g[i].w;
ans += g[i].p;
} else {
ans += g[i].ppw * n;
break;
}
}
printf("%.2lf", ans);
return 0;
}
大体和前面的鬼东西没什么区别 但是更!快!也!更!爽!
前面的能看懂后面这个也能懂(
THE END